1 /*
2  * Copyright (C) 2020 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 #pragma once
18 
19 #include "TimeMachine.h"
20 #include "TransactionLog.h"
21 
22 namespace android::mediametrics {
23 
24 /**
25  * AnalyticsState consists of a TimeMachine and TransactionLog for a set
26  * of MediaMetrics Items.
27  *
28  * One can add new Items with the submit() method.
29  *
30  * The AnalyticsState may be cleared or duplicated to preserve state after crashes
31  * in services are detected.
32  *
33  * As its members may not be moveable due to mutexes, we use this encapsulation
34  * with a shared pointer in order to save it or duplicate it.
35  */
36 class AnalyticsState {
37 public:
38     /**
39      * Returns success if AnalyticsState accepts the item.
40      *
41      * A trusted source can create a new key, an untrusted source
42      * can only modify the key if the uid will match that authorized
43      * on the existing key.
44      *
45      * \param item the item to be submitted.
46      * \param isTrusted whether the transaction comes from a trusted source.
47      *        In this case, a trusted source is verified by binder
48      *        UID to be a system service by MediaMetrics service.
49      *        Do not use true if you haven't really checked!
50      *
51      * \return NO_ERROR on success or
52      *         PERMISSION_DENIED if the item cannot be put into the AnalyticsState.
53      */
submit(const std::shared_ptr<const mediametrics::Item> & item,bool isTrusted)54     status_t submit(const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted) {
55         return mTimeMachine.put(item, isTrusted) ?: mTransactionLog.put(item);
56     }
57 
58     /**
59      * Returns the TimeMachine.
60      *
61      * The TimeMachine object is internally locked, so access is safe and defined,
62      * but multiple threaded access may change results after calling.
63      */
timeMachine()64     TimeMachine& timeMachine() { return mTimeMachine; }
timeMachine()65     const TimeMachine& timeMachine() const { return mTimeMachine; }
66 
67     /**
68      * Returns the TransactionLog.
69      *
70      * The TransactionLog object is internally locked, so access is safe and defined,
71      * but multiple threaded access may change results after calling.
72      */
transactionLog()73     TransactionLog& transactionLog() { return mTransactionLog; }
transactionLog()74     const TransactionLog& transactionLog() const { return mTransactionLog; }
75 
76     /**
77      * Returns a pair consisting of the dump string, and the number of lines in the string.
78      *
79      * The number of lines in the returned pair is used as an optimization
80      * for subsequent line limiting.
81      *
82      * The TimeMachine and the TransactionLog are dumped separately under
83      * different locks, so may not be 100% consistent with the last data
84      * delivered.
85      *
86      * \param lines the maximum number of lines in the string returned.
87      * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
88      * \param prefix the desired key prefix to match (nullptr shows all)
89      */
90     std::pair<std::string, int32_t> dump(
91             int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
92         std::stringstream ss;
93         int32_t ll = lines;
94 
95         if (ll > 0) {
96             ss << "TransactionLog: gc(" << mTransactionLog.getGarbageCollectionCount() << ")\n";
97             --ll;
98         }
99         if (ll > 0) {
100             auto [s, l] = mTransactionLog.dump(ll, sinceNs, prefix);
101             ss << s;
102             ll -= l;
103         }
104         if (ll > 0) {
105             ss << "TimeMachine: gc(" << mTimeMachine.getGarbageCollectionCount() << ")\n";
106             --ll;
107         }
108         if (ll > 0) {
109             auto [s, l] = mTimeMachine.dump(ll, sinceNs, prefix);
110             ss << s;
111             ll -= l;
112         }
113         return { ss.str(), lines - ll };
114     }
115 
116     /**
117      * Clears the AnalyticsState.
118      */
clear()119     void clear() {
120         mTimeMachine.clear();
121         mTransactionLog.clear();
122     }
123 
124 private:
125     // Note: TimeMachine and TransactionLog are individually locked.
126     // Access to these objects under multiple threads will be weakly synchronized,
127     // which is acceptable as modifications only increase the history (or with GC,
128     // eliminates very old history).
129 
130     TimeMachine    mTimeMachine;
131     TransactionLog mTransactionLog;
132 };
133 
134 } // namespace android::mediametrics
135