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

Commit c9b6f8bc authored by Andy Hung's avatar Andy Hung
Browse files

MediaMetricsService: Restrict session ids to those from MediaMetricsManager

Test: atest AudioTrackTest#testSetLogSessionId
Test: adb shell dumpsys media.metrics
Bug: 193265974
Change-Id: I5e165870b29dc8349a577b0c581a49e2bc60470c
parent 22cd76f5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -148,7 +148,8 @@ cc_library {
        "statsd_mediaparser.cpp",
        "statsd_nuplayer.cpp",
        "statsd_recorder.cpp",
        "StringUtils.cpp"
        "StringUtils.cpp",
        "ValidateId.cpp",
    ],

    proto: {
+3 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "AudioTypes.h"           // string to int conversions
#include "MediaMetricsService.h"  // package info
#include "StringUtils.h"
#include "ValidateId.h"

#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"

@@ -562,7 +563,7 @@ void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
        const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
        const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
        // Android S
        const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
        const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);

        LOG(LOG_LEVEL) << "key:" << key
              << " id:" << id
@@ -717,7 +718,7 @@ void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
                 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
        const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
        // Android S
        const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
        const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);

        LOG(LOG_LEVEL) << "key:" << key
              << " id:" << id
+123 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT 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 <list>
#include <sstream>
#include <unordered_map>

namespace android::mediametrics {

/**
 * LruSet keeps a set of the last "Size" elements added or accessed.
 *
 * (Lru stands for least-recently-used eviction policy).
 *
 * Runs in O(1) time for add, remove, and check.  Internally implemented
 * with an unordered_map and a list.  In order to remove elements,
 * a list iterator is stored in the unordered_map
 * (noting that std::list::erase() contractually
 * does not affect iterators other than the one erased).
 */

template <typename T>
class LruSet {
    const size_t mMaxSize;
    std::list<T> mAccessOrder;                 // front is the most recent, back is the oldest.
    // item T with its access order iterator.
    std::unordered_map<T, typename std::list<T>::iterator> mMap;

public:
    /**
     * Constructs a LruSet which checks whether the element was
     * accessed or added recently.
     *
     * The parameter maxSize is used to cap growth of LruSet;
     * eviction is based on least recently used LRU.
     * If maxSize is zero, the LruSet contains no elements
     * and check() always returns false.
     *
     * \param maxSize the maximum number of elements that are tracked.
     */
    explicit LruSet(size_t maxSize) : mMaxSize(maxSize) {}

    /**
     * Returns the number of entries in the LruSet.
     *
     * This is a number between 0 and maxSize.
     */
    size_t size() const {
        return mMap.size();
    }

    /** Clears the container contents. */
    void clear() {
        mMap.clear();
        mAccessOrder.clear();
    }

    /** Returns a string dump of the last n entries. */
    std::string dump(size_t n) const {
        std::stringstream ss;
        auto it = mAccessOrder.cbegin();
        for (size_t i = 0; i < n && it != mAccessOrder.cend(); ++i) {
            ss << *it++ << "\n";
        }
        return ss.str();
    }

    /** Adds a new item to the set. */
    void add(const T& t) {
        if (mMaxSize == 0) return;
        auto it = mMap.find(t);
        if (it != mMap.end()) { // already exists.
            mAccessOrder.erase(it->second);  // move-to-front on the chronologically ordered list.
        } else if (mAccessOrder.size() >= mMaxSize) {
            const T last = mAccessOrder.back();
            mAccessOrder.pop_back();
            mMap.erase(last);
        }
        mAccessOrder.push_front(t);
        mMap[t] = mAccessOrder.begin();
    }

    /**
     * Removes an item from the set.
     *
     * \param t item to be removed.
     * \return false if the item doesn't exist.
     */
    bool remove(const T& t) {
        auto it = mMap.find(t);
        if (it == mMap.end()) return false;
        mAccessOrder.erase(it->second);
        mMap.erase(it);
        return true;
    }

    /** Returns true if t is present (and moves the access order of t to the front). */
    bool check(const T& t) { // not const, as it adjusts the least-recently-used order.
        auto it = mMap.find(t);
        if (it == mMap.end()) return false;
        mAccessOrder.erase(it->second);
        mAccessOrder.push_front(it->first);
        it->second = mAccessOrder.begin();
        return true;
    }
};

} // namespace android::mediametrics
+13 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <utils/Log.h>

#include "MediaMetricsService.h"
#include "ValidateId.h"
#include "iface_statsd.h"

#include <pwd.h> //getpwuid
@@ -204,6 +205,15 @@ status_t MediaMetricsService::submitInternal(mediametrics::Item *item, bool rele
    // now attach either the item or its dup to a const shared pointer
    std::shared_ptr<const mediametrics::Item> sitem(release ? item : item->dup());

    // register log session ids with singleton.
    if (startsWith(item->getKey(), "metrics.manager")) {
        std::string logSessionId;
        if (item->get("logSessionId", &logSessionId)
                && mediametrics::stringutils::isLogSessionId(logSessionId.c_str())) {
            mediametrics::ValidateId::get()->registerId(logSessionId);
        }
    }

    (void)mAudioAnalytics.submit(sitem, isTrusted);

    (void)dump2Statsd(sitem, mStatsdLog);  // failure should be logged in function.
@@ -309,6 +319,9 @@ status_t MediaMetricsService::dump(int fd, const Vector<String16>& args)
                result << "-- some lines may be truncated --\n";
            }

            result << "LogSessionId:\n"
                   << mediametrics::ValidateId::get()->dump();

            // Dump the statsd atoms we sent out.
            result << "Statsd atoms:\n"
                   << mStatsdLog->dumpToString("  " /* prefix */,
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT 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 "MediaMetricsService"  // not ValidateId
#include <utils/Log.h>

#include "ValidateId.h"

namespace android::mediametrics {

std::string ValidateId::dump() const
{
    std::stringstream ss;
    ss << "Entries:" << mIdSet.size() << "  InvalidIds:" << mInvalidIds << "\n";
    ss << mIdSet.dump(10);
    return ss.str();
}

void ValidateId::registerId(const std::string& id)
{
    if (id.empty()) return;
    if (!mediametrics::stringutils::isLogSessionId(id.c_str())) {
        ALOGW("%s: rejecting malformed id %s", __func__, id.c_str());
        return;
    }
    ALOGV("%s: registering %s", __func__, id.c_str());
    mIdSet.add(id);
}

const std::string& ValidateId::validateId(const std::string& id)
{
    static const std::string empty{};
    if (id.empty()) return empty;

    // reject because the id is malformed
    if (!mediametrics::stringutils::isLogSessionId(id.c_str())) {
        ALOGW("%s: rejecting malformed id %s", __func__, id.c_str());
        ++mInvalidIds;
        return empty;
    }

    // reject because the id is unregistered
    if (!mIdSet.check(id)) {
        ALOGW("%s: rejecting unregistered id %s", __func__, id.c_str());
        ++mInvalidIds;
        return empty;
    }
    return id;
}

} // namespace android::mediametrics
Loading