blob: 7da85212dce1c2491f1201a0c0537eaa4c877b27 [file] [log] [blame]
/*
* 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_MEDIA_NBLOG_MERGER_H
#define ANDROID_MEDIA_NBLOG_MERGER_H
#include <memory>
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include <audio_utils/fifo.h>
#include <media/nblog/PerformanceAnalysis.h>
#include <media/nblog/Reader.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <utils/Thread.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
namespace android {
class String16;
class String8;
namespace NBLog {
struct Shared;
// TODO update comments to reflect current functionalities
// This class is used to read data from each thread's individual FIFO in shared memory
// and write it to a single FIFO in local memory.
class Merger : public RefBase {
public:
Merger(const void *shared, size_t size);
~Merger() override = default;
void addReader(const sp<NBLog::Reader> &reader);
// TODO add removeReader
void merge();
// FIXME This is returning a reference to a shared variable that needs a lock
const std::vector<sp<Reader>>& getReaders() const;
private:
// vector of the readers the merger is supposed to merge from.
// every reader reads from a writer's buffer
// FIXME Needs to be protected by a lock
std::vector<sp<Reader>> mReaders;
Shared * const mShared; // raw pointer to shared memory
std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
};
// This class has a pointer to the FIFO in local memory which stores the merged
// data collected by NBLog::Merger from all Readers. It is used to process
// this data and write the result to PerformanceAnalysis.
class MergeReader : public Reader {
public:
MergeReader(const void *shared, size_t size, Merger &merger);
// process a particular snapshot of the reader
void processSnapshot(Snapshot &snap, int author);
// call getSnapshot of the content of the reader's buffer and process the data
void getAndProcessSnapshot();
// check for periodic push of performance data to media metrics, and perform
// the send if it is time to do so.
void checkPushToMediaMetrics();
void dump(int fd, const Vector<String16>& args);
private:
// FIXME Needs to be protected by a lock,
// because even though our use of it is read-only there may be asynchronous updates
// The object is owned by the Merger class.
const std::vector<sp<Reader>>& mReaders;
// analyzes, compresses and stores the merged data
// contains a separate instance for every author (thread), and for every source file
// location within each author
ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
// compresses and stores audio performance data from each thread's buffers.
// first parameter is author, i.e. thread index.
std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData;
// how often to push data to Media Metrics
static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours
// handle author entry by looking up the author's name and appending it to the body
// returns number of bytes read from fmtEntry
void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
};
// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
// when triggered, it awakes for a lapse of time, during which it periodically merges; if
// retriggered, the timeout is reset.
// The thread is triggered on AudioFlinger binder activity.
class MergeThread : public Thread {
public:
MergeThread(Merger &merger, MergeReader &mergeReader);
~MergeThread() override;
// Reset timeout and activate thread to merge periodically if it's idle
void wakeup();
// Set timeout period until the merging thread goes idle again
void setTimeoutUs(int time);
private:
bool threadLoop() override;
// the merger who actually does the work of merging the logs
Merger& mMerger;
// the mergereader used to process data merged by mMerger
MergeReader& mMergeReader;
// mutex for the condition variable
Mutex mMutex;
// condition variable to activate merging on timeout >= 0
Condition mCond;
// time left until the thread blocks again (in microseconds)
int mTimeoutUs;
// merging period when the thread is awake
static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
// initial timeout value when triggered
static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
};
} // namespace NBLog
} // namespace android
#endif // ANDROID_MEDIA_NBLOG_MERGER_H