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