Default implementation for BroadcastRadio AIDL HAL

Default implementation for BroadcastRadio AIDL HAL is based on
default implementation for HIDL 2.0, with necessary data type
conversion. The callback for IBroadcastRadio interface is
initialized as nullptr.

Bug: 170336130
Test: m -j
Change-Id: Id521573116c565c42af16333cad73c5dd0583420
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
new file mode 100644
index 0000000..a284651
--- /dev/null
+++ b/broadcastradio/common/utilsaidl/Utils.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BcRadioAidlDef.utils"
+
+#include "broadcastradio-utils-aidl/Utils.h"
+
+#include <android-base/logging.h>
+
+#include <math/HashCombine.h>
+
+namespace aidl::android::hardware::broadcastradio {
+
+namespace utils {
+
+namespace {
+
+using ::std::string;
+using ::std::vector;
+
+const int64_t kValueForNotFoundIdentifier = 0;
+
+bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+    return hasId(a, type) && hasId(b, type);
+}
+
+bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
+    if (!bothHaveId(a, b, type)) {
+        return false;
+    }
+    /* We should check all Ids of a given type (ie. other AF),
+     * but it doesn't matter for default implementation.
+     */
+    return getId(a, type) == getId(b, type);
+}
+
+int getHdSubchannel(const ProgramSelector& sel) {
+    int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, /* defaultValue */ 0);
+    hdSidExt >>= 32;        // Station ID number
+    return hdSidExt & 0xF;  // HD Radio subchannel
+}
+
+bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
+    // iterate through primaryId and secondaryIds
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (it->type == type) {
+            if (val != nullptr) {
+                *val = it->value;
+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
+}  // namespace
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
+
+IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
+    : mSel(sel), mPos(pos) {}
+
+const IdentifierIterator IdentifierIterator::operator++(int) {
+    IdentifierIterator i = *this;
+    mPos++;
+    return i;
+}
+
+IdentifierIterator& IdentifierIterator::operator++() {
+    ++mPos;
+    return *this;
+}
+
+IdentifierIterator::refType IdentifierIterator::operator*() const {
+    if (mPos == 0) {
+        return getSelector().primaryId;
+    }
+
+    // mPos is 1-based for secondary identifiers
+    DCHECK(mPos <= getSelector().secondaryIds.size());
+    return getSelector().secondaryIds[mPos - 1];
+}
+
+bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
+    // Check, if both iterators points at the same selector.
+    if (reinterpret_cast<intptr_t>(&getSelector()) !=
+        reinterpret_cast<intptr_t>(&rhs.getSelector())) {
+        return false;
+    }
+
+    return mPos == rhs.mPos;
+}
+
+int32_t resultToInt(Result result) {
+    return static_cast<int32_t>(result);
+}
+
+FrequencyBand getBand(int64_t freq) {
+    // keep in sync with
+    // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
+    if (freq < 30) return FrequencyBand::UNKNOWN;
+    if (freq < 500) return FrequencyBand::AM_LW;
+    if (freq < 1705) return FrequencyBand::AM_MW;
+    if (freq < 30000) return FrequencyBand::AM_SW;
+    if (freq < 60000) return FrequencyBand::UNKNOWN;
+    if (freq < 110000) return FrequencyBand::FM;
+    return FrequencyBand::UNKNOWN;
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+    IdentifierType type = b.primaryId.type;
+
+    switch (type) {
+        case IdentifierType::HD_STATION_ID_EXT:
+        case IdentifierType::RDS_PI:
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+            return getHdSubchannel(b) == 0 &&
+                   haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
+        case IdentifierType::DAB_SID_EXT:
+            return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+        case IdentifierType::DRMO_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+        case IdentifierType::SXM_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+        default:  // includes all vendor types
+            LOG(WARNING) << "unsupported program type: " << toString(type);
+            return false;
+    }
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
+    return maybeGetId(sel, type, /* val */ nullptr);
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
+    int64_t val;
+
+    if (maybeGetId(sel, type, &val)) {
+        return val;
+    }
+
+    LOG(WARNING) << "identifier not found: " << toString(type);
+    return kValueForNotFoundIdentifier;
+}
+
+int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
+    if (!hasId(sel, type)) {
+        return defaultValue;
+    }
+    return getId(sel, type);
+}
+
+vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
+    vector<int> ret;
+
+    // iterate through primaryId and secondaryIds
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (it->type == type) {
+            ret.push_back(it->value);
+        }
+    }
+
+    return ret;
+}
+
+bool isSupported(const Properties& prop, const ProgramSelector& sel) {
+    for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
+         it++) {
+        if (hasId(sel, *it)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool isValid(const ProgramIdentifier& id) {
+    int64_t val = id.value;
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, const string& message) {
+        if (!condition) {
+            valid = false;
+            LOG(ERROR) << "identifier not valid, expected " << message;
+        }
+    };
+
+    switch (id.type) {
+        case IdentifierType::INVALID:
+            expect(false, "IdentifierType::INVALID");
+            break;
+        case IdentifierType::DAB_FREQUENCY_KHZ:
+            expect(val > 100000u, "f > 100MHz");
+            [[fallthrough]];
+        case IdentifierType::AMFM_FREQUENCY_KHZ:
+        case IdentifierType::DRMO_FREQUENCY_KHZ:
+            expect(val > 100u, "f > 100kHz");
+            expect(val < 10000000u, "f < 10GHz");
+            break;
+        case IdentifierType::RDS_PI:
+            expect(val != 0u, "RDS PI != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::HD_STATION_ID_EXT: {
+            int64_t stationId = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            int64_t subchannel = val & 0xF;  // 4bit
+            val >>= 4;
+            int64_t freq = val & 0x3FFFF;  // 18bit
+            expect(stationId != 0u, "HD station id != 0");
+            expect(subchannel < 8u, "HD subch < 8");
+            expect(freq > 100u, "f > 100kHz");
+            expect(freq < 10000000u, "f < 10GHz");
+            break;
+        }
+        case IdentifierType::HD_STATION_NAME: {
+            while (val > 0) {
+                char ch = static_cast<char>(val & 0xFF);
+                val >>= 8;
+                expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
+                       "HD_STATION_NAME does not match [A-Z0-9]+");
+            }
+            break;
+        }
+        case IdentifierType::DAB_SID_EXT: {
+            int64_t sid = val & 0xFFFF;  // 16bit
+            val >>= 16;
+            int64_t ecc = val & 0xFF;  // 8bit
+            expect(sid != 0u, "DAB SId != 0");
+            expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+            break;
+        }
+        case IdentifierType::DAB_ENSEMBLE:
+            expect(val != 0u, "DAB ensemble != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::DAB_SCID:
+            expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+            expect(val <= 0xFFFu, "12bit id");
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            expect(val != 0u, "DRM SId != 0");
+            expect(val <= 0xFFFFFFu, "24bit id");
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            expect(val != 0u, "SXM SId != 0");
+            expect(val <= 0xFFFFFFFFu, "32bit id");
+            break;
+        case IdentifierType::SXM_CHANNEL:
+            expect(val < 1000u, "SXM channel < 1000");
+            break;
+        case IdentifierType::VENDOR_START:
+        case IdentifierType::VENDOR_END:
+            // skip
+            break;
+    }
+
+    return valid;
+}
+
+bool isValid(const ProgramSelector& sel) {
+    // iterate through primaryId and secondaryIds
+    for (auto it = begin(sel); it != end(sel); it++) {
+        if (!isValid(*it)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
+    return {type, value};
+}
+
+ProgramSelector makeSelectorAmfm(int32_t frequency) {
+    ProgramSelector sel = {};
+    sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
+    return sel;
+}
+
+ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble) {
+    ProgramSelector sel = {};
+    // TODO(243686545): Have a helper function to create the sidExt instead of
+    // passing the whole identifier here. Something like makeDabSidExt.
+    sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
+    vector<ProgramIdentifier> secondaryIds = {
+            makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
+            // TODO(243686545): Include frequency here when the helper method to
+            // translate between ensemble and frequency is implemented.
+    };
+    sel.secondaryIds = std::move(secondaryIds);
+    return sel;
+}
+
+bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
+    if (filter.identifierTypes.size() > 0) {
+        auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
+            return id.type == type;
+        };
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
+                                     filter.identifierTypes.end(), typeEquals);
+        if (it == end(sel)) {
+            return false;
+        }
+    }
+
+    if (filter.identifiers.size() > 0) {
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
+                                     filter.identifiers.end());
+        if (it == end(sel)) {
+            return false;
+        }
+    }
+
+    if (!filter.includeCategories && sel.primaryId.type == IdentifierType::DAB_ENSEMBLE) {
+        return false;
+    }
+
+    return true;
+}
+
+size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
+    const ProgramIdentifier& id = info.selector.primaryId;
+
+    // This is not the best hash implementation, but good enough for default HAL
+    // implementation and tests.
+    size_t h = 0;
+    ::android::hashCombineSingle(h, id.type);
+    ::android::hashCombineSingle(h, id.value);
+    return h;
+}
+
+bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
+    const ProgramIdentifier& id1 = info1.selector.primaryId;
+    const ProgramIdentifier& id2 = info2.selector.primaryId;
+    return id1.type == id2.type && id1.value == id2.value;
+}
+
+void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
+    if (chunk.purge) {
+        list->clear();
+    }
+
+    list->insert(chunk.modified.begin(), chunk.modified.end());
+
+    if (!chunk.removed.has_value()) {
+        return;
+    }
+
+    for (auto& id : chunk.removed.value()) {
+        if (id.has_value()) {
+            ProgramInfo info = {};
+            info.selector.primaryId = id.value();
+            list->erase(info);
+        }
+    }
+}
+
+std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
+    auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
+
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
+    if (it == info.metadata.end()) {
+        return std::nullopt;
+    }
+
+    std::string metadataString;
+    switch (it->getTag()) {
+        case Metadata::rdsPs:
+            metadataString = it->get<Metadata::rdsPs>();
+            break;
+        case Metadata::rdsPty:
+            metadataString = std::to_string(it->get<Metadata::rdsPty>());
+            break;
+        case Metadata::rbdsPty:
+            metadataString = std::to_string(it->get<Metadata::rbdsPty>());
+            break;
+        case Metadata::rdsRt:
+            metadataString = it->get<Metadata::rdsRt>();
+            break;
+        case Metadata::songTitle:
+            metadataString = it->get<Metadata::songTitle>();
+            break;
+        case Metadata::songArtist:
+            metadataString = it->get<Metadata::songArtist>();
+            break;
+        case Metadata::songAlbum:
+            metadataString = it->get<Metadata::songAlbum>();
+            break;
+        case Metadata::stationIcon:
+            metadataString = std::to_string(it->get<Metadata::stationIcon>());
+            break;
+        case Metadata::albumArt:
+            metadataString = std::to_string(it->get<Metadata::albumArt>());
+            break;
+        case Metadata::programName:
+            metadataString = it->get<Metadata::programName>();
+            break;
+        case Metadata::dabEnsembleName:
+            metadataString = it->get<Metadata::dabEnsembleName>();
+            break;
+        case Metadata::dabEnsembleNameShort:
+            metadataString = it->get<Metadata::dabEnsembleNameShort>();
+            break;
+        case Metadata::dabServiceName:
+            metadataString = it->get<Metadata::dabServiceName>();
+            break;
+        case Metadata::dabServiceNameShort:
+            metadataString = it->get<Metadata::dabServiceNameShort>();
+            break;
+        case Metadata::dabComponentName:
+            metadataString = it->get<Metadata::dabComponentName>();
+            break;
+        case Metadata::dabComponentNameShort:
+            metadataString = it->get<Metadata::dabComponentNameShort>();
+            break;
+        default:
+            LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
+            return std::nullopt;
+    }
+    return metadataString;
+}
+
+ProgramIdentifier makeHdRadioStationName(const string& name) {
+    constexpr size_t maxlen = 8;
+
+    string shortName;
+    shortName.reserve(maxlen);
+
+    const auto& loc = std::locale::classic();
+    for (const char& ch : name) {
+        if (!std::isalnum(ch, loc)) {
+            continue;
+        }
+        shortName.push_back(std::toupper(ch, loc));
+        if (shortName.length() >= maxlen) {
+            break;
+        }
+    }
+
+    // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
+    // in little-endian order. For example, "Abc" is converted to 0x434241.
+    int64_t val = 0;
+    for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
+        val <<= 8;
+        val |= static_cast<char>(*rit);
+    }
+
+    return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
+}
+
+}  // namespace utils
+
+utils::IdentifierIterator begin(const ProgramSelector& sel) {
+    return utils::IdentifierIterator(sel);
+}
+
+utils::IdentifierIterator end(const ProgramSelector& sel) {
+    return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
+}
+
+}  // namespace aidl::android::hardware::broadcastradio