Add format check utils method for bcradio metadata

Added format check method for AIDL broadcast radio HAL metadata in
AIDL utils library. Also corrected local variable name in
getMetadataString method.

Bug: 318868350
Test: atest broadcastradio_utils_aidl_test
Change-Id: I8220e2845143931e99b4e4da0e07c9cae585588e
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index 3ced685..25c96d0 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -143,6 +143,8 @@
 
 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
 
+bool isValidMetadata(const Metadata& metadata);
+
 struct ProgramSelectorComparator {
     bool operator()(const ProgramSelector& lhs, const ProgramSelector& rhs) const;
 };
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h
index e411aa4..734758d 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/UtilsV2.h
@@ -28,6 +28,7 @@
 
 bool isValidV2(const ProgramIdentifier& id);
 bool isValidV2(const ProgramSelector& sel);
+bool isValidMetadataV2(const Metadata& metadata);
 std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag);
 
 }  // namespace utils
diff --git a/broadcastradio/common/utilsaidl/src/Utils.cpp b/broadcastradio/common/utilsaidl/src/Utils.cpp
index b647442..ddc5b8d 100644
--- a/broadcastradio/common/utilsaidl/src/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/src/Utils.cpp
@@ -442,9 +442,9 @@
 }
 
 std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
-    auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
+    auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
 
-    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
     if (it == info.metadata.end()) {
         return std::nullopt;
     }
@@ -579,6 +579,45 @@
     return getHdFrequency(sel);
 }
 
+bool isValidMetadata(const Metadata& metadata) {
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, const std::string& message) {
+        if (!condition) {
+            valid = false;
+            LOG(ERROR) << "metadata not valid, expected " << message;
+        }
+    };
+
+    switch (metadata.getTag()) {
+        case Metadata::rdsPty:
+            expect(metadata.get<Metadata::rdsPty>() >= 0, "RDS PTY >= 0");
+            expect(metadata.get<Metadata::rdsPty>() <= std::numeric_limits<uint8_t>::max(),
+                   "8bit RDS PTY");
+            break;
+        case Metadata::rbdsPty:
+            expect(metadata.get<Metadata::rbdsPty>() >= 0, "RBDS PTY >= 0");
+            expect(metadata.get<Metadata::rbdsPty>() <= std::numeric_limits<uint8_t>::max(),
+                   "8bit RBDS PTY");
+            break;
+        case Metadata::dabEnsembleNameShort:
+            expect(metadata.get<Metadata::dabEnsembleNameShort>().size() <= 8,
+                   "Dab ensemble name abbreviated length <= 8");
+            break;
+        case Metadata::dabServiceNameShort:
+            expect(metadata.get<Metadata::dabServiceNameShort>().size() <= 8,
+                   "Dab component name abbreviated length <= 8");
+            break;
+        case Metadata::dabComponentNameShort:
+            expect(metadata.get<Metadata::dabComponentNameShort>().size() <= 8,
+                   "Dab component name abbreviated length <= 8");
+            break;
+        default:
+            break;
+    }
+    return valid;
+}
+
 bool parseArgInt(const std::string& s, int* out) {
     return ::android::base::ParseInt(s, out);
 }
diff --git a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
index ef739df..6c75759 100644
--- a/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
+++ b/broadcastradio/common/utilsaidl/src/UtilsV2.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "BcRadioAidlDef.utilsV2"
 
 #include "broadcastradio-utils-aidl/UtilsV2.h"
+#include "broadcastradio-utils-aidl/Utils.h"
 
 #include <android-base/logging.h>
 #include <android-base/strings.h>
@@ -137,10 +138,33 @@
     return isValidV2(sel.primaryId);
 }
 
-std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
-    auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
+bool isValidMetadataV2(const Metadata& metadata) {
+    if (!isValidMetadata(metadata)) {
+        return false;
+    }
 
-    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
+    if (metadata.getTag() == Metadata::hdStationNameShort) {
+        if (metadata.get<Metadata::hdStationNameShort>().size() > 12) {
+            LOG(ERROR) << "metadata not valid, expected HD short name length <= 12";
+            return false;
+        }
+    } else if (metadata.getTag() == Metadata::hdSubChannelsAvailable) {
+        if (metadata.get<Metadata::hdSubChannelsAvailable>() < 0) {
+            LOG(ERROR) << "metadata not valid, expected HD subchannels available >= 0";
+            return false;
+        } else if (metadata.get<Metadata::hdSubChannelsAvailable>() >
+                   std::numeric_limits<uint8_t>::max()) {
+            LOG(ERROR) << "metadata not valid, expected 8bit HD subchannels available";
+            return false;
+        }
+    }
+    return true;
+}
+
+std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
+    auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
+
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
     if (it == info.metadata.end()) {
         return std::nullopt;
     }
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
index b2dc94a..b630a67 100644
--- a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsTest.cpp
@@ -32,8 +32,75 @@
 constexpr uint64_t kHdStationId = 0xA0000001u;
 constexpr uint64_t kHdSubChannel = 1u;
 constexpr uint64_t kHdFrequency = 97700u;
+
+struct IsValidMetadataTestCase {
+    std::string name;
+    Metadata metadata;
+    bool valid;
+};
+
+std::vector<IsValidMetadataTestCase> getIsValidMetadataTestCases() {
+    return std::vector<IsValidMetadataTestCase>({
+            IsValidMetadataTestCase{.name = "valid_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rds_pty",
+                                    .metadata = Metadata::make<Metadata::rdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "valid_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(1),
+                                    .valid = true},
+            IsValidMetadataTestCase{.name = "negative_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(-1),
+                                    .valid = false},
+            IsValidMetadataTestCase{.name = "large_rbds_pty",
+                                    .metadata = Metadata::make<Metadata::rbdsPty>(256),
+                                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_ensemble_name_short",
+                    .metadata = Metadata::make<Metadata::dabEnsembleNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_service_name_short",
+                    .metadata = Metadata::make<Metadata::dabServiceNameShort>("name_long"),
+                    .valid = false},
+            IsValidMetadataTestCase{
+                    .name = "valid_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name"),
+                    .valid = true},
+            IsValidMetadataTestCase{
+                    .name = "too_long_dab_component_name_short",
+                    .metadata = Metadata::make<Metadata::dabComponentNameShort>("name_long"),
+                    .valid = false},
+    });
+}
 }  // namespace
 
+class IsValidMetadataTest : public testing::TestWithParam<IsValidMetadataTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataTests, IsValidMetadataTest,
+                         testing::ValuesIn(getIsValidMetadataTestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataTest, IsValidMetadata) {
+    IsValidMetadataTestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadata(testParam.metadata), testParam.valid);
+}
+
 TEST(BroadcastRadioUtilsTest, HasIdWithPrimaryIdType) {
     ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
 
diff --git a/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
new file mode 100644
index 0000000..cf9f9e9
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/test/BroadcastRadioUtilsV2Test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <broadcastradio-utils-aidl/UtilsV2.h>
+#include <gtest/gtest.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace {
+struct IsValidMetadataV2TestCase {
+    std::string name;
+    Metadata metadata;
+    bool valid;
+};
+
+std::vector<IsValidMetadataV2TestCase> getIsValidMetadataV2TestCases() {
+    return std::vector<IsValidMetadataV2TestCase>({
+            IsValidMetadataV2TestCase{.name = "valid_rds_pty",
+                                      .metadata = Metadata::make<Metadata::rdsPty>(1),
+                                      .valid = true},
+            IsValidMetadataV2TestCase{.name = "negative_rds_pty",
+                                      .metadata = Metadata::make<Metadata::rdsPty>(-1),
+                                      .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "valid_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_short"),
+                    .valid = true},
+            IsValidMetadataV2TestCase{
+                    .name = "too_long_hd_station_name_short",
+                    .metadata = Metadata::make<Metadata::hdStationNameShort>("name_too_long"),
+                    .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "valid_hd_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(1),
+                    .valid = true},
+            IsValidMetadataV2TestCase{
+                    .name = "negative_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(-1),
+                    .valid = false},
+            IsValidMetadataV2TestCase{
+                    .name = "large_subchannel_available",
+                    .metadata = Metadata::make<Metadata::hdSubChannelsAvailable>(256),
+                    .valid = false},
+    });
+}
+}  // namespace
+
+class IsValidMetadataV2Test : public testing::TestWithParam<IsValidMetadataV2TestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(IsValidMetadataV2Tests, IsValidMetadataV2Test,
+                         testing::ValuesIn(getIsValidMetadataV2TestCases()),
+                         [](const testing::TestParamInfo<IsValidMetadataV2Test::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(IsValidMetadataV2Test, IsValidMetadataV2) {
+    IsValidMetadataV2TestCase testParam = GetParam();
+
+    ASSERT_EQ(utils::isValidMetadataV2(testParam.metadata), testParam.valid);
+}
+
+}  // namespace aidl::android::hardware::broadcastradio