1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_MEDIA_NBLOG_MERGER_H 18 #define ANDROID_MEDIA_NBLOG_MERGER_H 19 20 #include <memory> 21 #include <stddef.h> 22 #include <stdint.h> 23 #include <vector> 24 25 #include <audio_utils/fifo.h> 26 #include <media/nblog/PerformanceAnalysis.h> 27 #include <media/nblog/Reader.h> 28 #include <utils/Condition.h> 29 #include <utils/Mutex.h> 30 #include <utils/RefBase.h> 31 #include <utils/Thread.h> 32 #include <utils/Timers.h> 33 #include <utils/Vector.h> 34 35 namespace android { 36 37 class String16; 38 class String8; 39 40 namespace NBLog { 41 42 struct Shared; 43 44 // TODO update comments to reflect current functionalities 45 46 // This class is used to read data from each thread's individual FIFO in shared memory 47 // and write it to a single FIFO in local memory. 48 class Merger : public RefBase { 49 public: 50 Merger(const void *shared, size_t size); 51 52 ~Merger() override = default; 53 54 void addReader(const sp<NBLog::Reader> &reader); 55 // TODO add removeReader 56 void merge(); 57 58 // FIXME This is returning a reference to a shared variable that needs a lock 59 const std::vector<sp<Reader>>& getReaders() const; 60 61 private: 62 // vector of the readers the merger is supposed to merge from. 63 // every reader reads from a writer's buffer 64 // FIXME Needs to be protected by a lock 65 std::vector<sp<Reader>> mReaders; 66 67 Shared * const mShared; // raw pointer to shared memory 68 std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself 69 std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO 70 }; 71 72 // This class has a pointer to the FIFO in local memory which stores the merged 73 // data collected by NBLog::Merger from all Readers. It is used to process 74 // this data and write the result to PerformanceAnalysis. 75 class MergeReader : public Reader { 76 public: 77 MergeReader(const void *shared, size_t size, Merger &merger); 78 79 // process a particular snapshot of the reader 80 void processSnapshot(Snapshot &snap, int author); 81 82 // call getSnapshot of the content of the reader's buffer and process the data 83 void getAndProcessSnapshot(); 84 85 // check for periodic push of performance data to media metrics, and perform 86 // the send if it is time to do so. 87 void checkPushToMediaMetrics(); 88 89 void dump(int fd, const Vector<String16>& args); 90 91 private: 92 // FIXME Needs to be protected by a lock, 93 // because even though our use of it is read-only there may be asynchronous updates 94 // The object is owned by the Merger class. 95 const std::vector<sp<Reader>>& mReaders; 96 97 // analyzes, compresses and stores the merged data 98 // contains a separate instance for every author (thread), and for every source file 99 // location within each author 100 ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis; 101 102 // compresses and stores audio performance data from each thread's buffers. 103 // first parameter is author, i.e. thread index. 104 std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData; 105 106 // how often to push data to Media Metrics 107 static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours 108 109 // handle author entry by looking up the author's name and appending it to the body 110 // returns number of bytes read from fmtEntry 111 void handleAuthor(const AbstractEntry &fmtEntry, String8 *body); 112 }; 113 114 // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot: 115 // when triggered, it awakes for a lapse of time, during which it periodically merges; if 116 // retriggered, the timeout is reset. 117 // The thread is triggered on AudioFlinger binder activity. 118 class MergeThread : public Thread { 119 public: 120 MergeThread(Merger &merger, MergeReader &mergeReader); 121 ~MergeThread() override; 122 123 // Reset timeout and activate thread to merge periodically if it's idle 124 void wakeup(); 125 126 // Set timeout period until the merging thread goes idle again 127 void setTimeoutUs(int time); 128 129 private: 130 bool threadLoop() override; 131 132 // the merger who actually does the work of merging the logs 133 Merger& mMerger; 134 135 // the mergereader used to process data merged by mMerger 136 MergeReader& mMergeReader; 137 138 // mutex for the condition variable 139 Mutex mMutex; 140 141 // condition variable to activate merging on timeout >= 0 142 Condition mCond; 143 144 // time left until the thread blocks again (in microseconds) 145 int mTimeoutUs; 146 147 // merging period when the thread is awake 148 static const int kThreadSleepPeriodUs = 1000000 /*1s*/; 149 150 // initial timeout value when triggered 151 static const int kThreadWakeupPeriodUs = 3000000 /*3s*/; 152 }; 153 154 } // namespace NBLog 155 } // namespace android 156 157 #endif // ANDROID_MEDIA_NBLOG_MERGER_H 158