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

Commit 8c83081a authored by Andy Hung's avatar Andy Hung
Browse files

MediaMetricsService: Use system_clock for TimedAction

This ensures AudioPowerUsage atoms are delivered
based on wallclock time.

Test: adb shell dumpsys media.metrics --all
Bug: 314810064
Change-Id: Ic98e6b48602f61792c40b21d57b809596fa136ff
parent 536fa6cb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -549,7 +549,7 @@ std::pair<std::string, int32_t> AudioPowerUsage::dump(int limit) const {

    int slot = 1;
    std::stringstream ss;
    ss << "AudioPowerUsage:\n";
    ss << "AudioPowerUsage interval " << mIntervalHours << " hours:\n";
    for (const auto &item : mItems) {
        if (slot >= limit - 1) {
            ss << "-- AudioPowerUsage may be truncated!\n";
+15 −4
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@
namespace android::mediametrics {

class TimedAction {
    // Use system_clock instead of steady_clock to include suspend time.
    using TimerClock = class std::chrono::system_clock;

    // Define granularity of wakeup to prevent delayed events if
    // device is suspended.
    static constexpr auto kWakeupInterval = std::chrono::minutes(15);
public:
    TimedAction() : mThread{[this](){threadLoop();}} {}

@@ -35,7 +41,7 @@ public:
    // TODO: return a handle for cancelling the action?
    template <typename T> // T is in units of std::chrono::duration.
    void postIn(const T& time, std::function<void()> f) {
        postAt(std::chrono::steady_clock::now() + time, f);
        postAt(TimerClock::now() + time, f);
    }

    template <typename T> // T is in units of std::chrono::time_point
@@ -75,16 +81,21 @@ private:
    void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
        std::unique_lock l(mLock);
        while (!mQuit) {
            auto sleepUntilTime = std::chrono::time_point<std::chrono::steady_clock>::max();
            auto sleepUntilTime = std::chrono::time_point<TimerClock>::max();
            if (!mMap.empty()) {
                sleepUntilTime = mMap.begin()->first;
                if (sleepUntilTime <= std::chrono::steady_clock::now()) {
                const auto now = TimerClock::now();
                if (sleepUntilTime <= now) {
                    auto node = mMap.extract(mMap.begin()); // removes from mMap.
                    l.unlock();
                    node.mapped()();
                    l.lock();
                    continue;
                }
                // Bionic uses CLOCK_MONOTONIC for its pthread_mutex regardless
                // of REALTIME specification, use kWakeupInterval to ensure minimum
                // granularity if suspended.
                sleepUntilTime = std::min(sleepUntilTime, now + kWakeupInterval);
            }
            mCondition.wait_until(l, sleepUntilTime);
        }
@@ -93,7 +104,7 @@ private:
    mutable std::mutex mLock;
    std::condition_variable mCondition GUARDED_BY(mLock);
    bool mQuit GUARDED_BY(mLock) = false;
    std::multimap<std::chrono::time_point<std::chrono::steady_clock>, std::function<void()>>
    std::multimap<std::chrono::time_point<TimerClock>, std::function<void()>>
            mMap GUARDED_BY(mLock); // multiple functions could execute at the same time.

    // needs to be initialized after the variables above, done in constructor initializer list.