1 /*
2  * Copyright 2017, 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 #pragma once
17 
18 #include "config/ConfigKey.h"
19 #include "statslog.h"
20 
21 #include <gtest/gtest_prod.h>
22 #include <log/log_time.h>
23 #include <list>
24 #include <mutex>
25 #include <string>
26 #include <vector>
27 
28 namespace android {
29 namespace os {
30 namespace statsd {
31 
32 struct ConfigStats {
33     int32_t uid;
34     int64_t id;
35     int32_t creation_time_sec;
36     int32_t deletion_time_sec = 0;
37     int32_t reset_time_sec = 0;
38     int32_t metric_count;
39     int32_t condition_count;
40     int32_t matcher_count;
41     int32_t alert_count;
42     bool is_valid;
43 
44     std::list<int32_t> broadcast_sent_time_sec;
45     std::list<int32_t> data_drop_time_sec;
46     std::list<std::pair<int32_t, int64_t>> dump_report_stats;
47 
48     // Stores how many times a matcher have been matched. The map size is capped by kMaxConfigCount.
49     std::map<const int64_t, int> matcher_stats;
50 
51     // Stores the number of output tuple of condition trackers when it's bigger than
52     // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
53     // it means some data has been dropped. The map size is capped by kMaxConfigCount.
54     std::map<const int64_t, int> condition_stats;
55 
56     // Stores the number of output tuple of metric producers when it's bigger than
57     // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
58     // it means some data has been dropped. The map size is capped by kMaxConfigCount.
59     std::map<const int64_t, int> metric_stats;
60 
61     // Stores the max number of output tuple of dimensions in condition across dimensions in what
62     // when it's bigger than kDimensionKeySizeSoftLimit. When you see the number is
63     // kDimensionKeySizeHardLimit +1, it means some data has been dropped. The map size is capped by
64     // kMaxConfigCount.
65     std::map<const int64_t, int> metric_dimension_in_condition_stats;
66 
67     // Stores the number of times an anomaly detection alert has been declared.
68     // The map size is capped by kMaxConfigCount.
69     std::map<const int64_t, int> alert_stats;
70 
71     // Stores the config ID for each sub-config used.
72     std::list<std::pair<const int64_t, const int32_t>> annotations;
73 };
74 
75 struct UidMapStats {
76     int32_t changes;
77     int32_t bytes_used;
78     int32_t dropped_changes;
79     int32_t deleted_apps = 0;
80 };
81 
82 // Keeps track of stats of statsd.
83 // Single instance shared across the process. All public methods are thread safe.
84 class StatsdStats {
85 public:
86     static StatsdStats& getInstance();
~StatsdStats()87     ~StatsdStats(){};
88 
89     // TODO: set different limit if the device is low ram.
90     const static int kDimensionKeySizeSoftLimit = 500;
91     const static int kDimensionKeySizeHardLimit = 800;
92 
93     // Per atom dimension key size limit
94     static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap;
95 
96     const static int kMaxConfigCountPerUid = 10;
97     const static int kMaxAlertCountPerConfig = 100;
98     const static int kMaxConditionCountPerConfig = 300;
99     const static int kMaxMetricCountPerConfig = 1000;
100     const static int kMaxMatcherCountPerConfig = 800;
101 
102     // The max number of old config stats we keep.
103     const static int kMaxIceBoxSize = 20;
104 
105     const static int kMaxLoggerErrors = 20;
106 
107     const static int kMaxSystemServerRestarts = 20;
108 
109     const static int kMaxTimestampCount = 20;
110 
111     const static int kMaxLogSourceCount = 50;
112 
113     // Max memory allowed for storing metrics per configuration. If this limit is exceeded, statsd
114     // drops the metrics data in memory.
115     static const size_t kMaxMetricsBytesPerConfig = 256 * 1024;
116 
117     // Soft memory limit per configuration. Once this limit is exceeded, we begin notifying the
118     // data subscriber that it's time to call getData.
119     static const size_t kBytesPerConfigTriggerGetData = 192 * 1024;
120 
121     // Cap the UID map's memory usage to this. This should be fairly high since the UID information
122     // is critical for understanding the metrics.
123     const static size_t kMaxBytesUsedUidMap = 50 * 1024;
124 
125     // The number of deleted apps that are stored in the uid map.
126     const static int kMaxDeletedAppsInUidMap = 100;
127 
128     /* Minimum period between two broadcasts in nanoseconds. */
129     static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
130 
131     /* Min period between two checks of byte size per config key in nanoseconds. */
132     static const int64_t kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
133 
134     // Maximum age (30 days) that files on disk can exist in seconds.
135     static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
136 
137     // Maximum number of files (1000) that can be in stats directory on disk.
138     static const int kMaxFileNumber = 1000;
139 
140     // Maximum size of all files that can be written to stats directory on disk.
141     static const int kMaxFileSize = 50 * 1024 * 1024;
142 
143     // How long to try to clear puller cache from last time
144     static const long kPullerCacheClearIntervalSec = 1;
145 
146     /**
147      * Report a new config has been received and report the static stats about the config.
148      *
149      * The static stats include: the count of metrics, conditions, matchers, and alerts.
150      * If the config is not valid, this config stats will be put into icebox immediately.
151      */
152     void noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
153                             int matchersCount, int alertCount,
154                             const std::list<std::pair<const int64_t, const int32_t>>& annotations,
155                             bool isValid);
156     /**
157      * Report a config has been removed.
158      */
159     void noteConfigRemoved(const ConfigKey& key);
160    /**
161      * Report a config has been reset when ttl expires.
162      */
163     void noteConfigReset(const ConfigKey& key);
164 
165     /**
166      * Report a broadcast has been sent to a config owner to collect the data.
167      */
168     void noteBroadcastSent(const ConfigKey& key);
169 
170     /**
171      * Report a config's metrics data has been dropped.
172      */
173     void noteDataDropped(const ConfigKey& key);
174 
175     /**
176      * Report metrics data report has been sent.
177      *
178      * The report may be requested via StatsManager API, or through adb cmd.
179      */
180     void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes);
181 
182     /**
183      * Report the size of output tuple of a condition.
184      *
185      * Note: only report when the condition has an output dimension, and the tuple
186      * count > kDimensionKeySizeSoftLimit.
187      *
188      * [key]: The config key that this condition belongs to.
189      * [id]: The id of the condition.
190      * [size]: The output tuple size.
191      */
192     void noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size);
193 
194     /**
195      * Report the size of output tuple of a metric.
196      *
197      * Note: only report when the metric has an output dimension, and the tuple
198      * count > kDimensionKeySizeSoftLimit.
199      *
200      * [key]: The config key that this metric belongs to.
201      * [id]: The id of the metric.
202      * [size]: The output tuple size.
203      */
204     void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
205 
206 
207     /**
208      * Report the max size of output tuple of dimension in condition across dimensions in what.
209      *
210      * Note: only report when the metric has an output dimension in condition, and the max tuple
211      * count > kDimensionKeySizeSoftLimit.
212      *
213      * [key]: The config key that this metric belongs to.
214      * [id]: The id of the metric.
215      * [size]: The output tuple size.
216      */
217     void noteMetricDimensionInConditionSize(const ConfigKey& key, const int64_t& id, int size);
218 
219     /**
220      * Report a matcher has been matched.
221      *
222      * [key]: The config key that this matcher belongs to.
223      * [id]: The id of the matcher.
224      */
225     void noteMatcherMatched(const ConfigKey& key, const int64_t& id);
226 
227     /**
228      * Report that an anomaly detection alert has been declared.
229      *
230      * [key]: The config key that this alert belongs to.
231      * [id]: The id of the alert.
232      */
233     void noteAnomalyDeclared(const ConfigKey& key, const int64_t& id);
234 
235     /**
236      * Report an atom event has been logged.
237      */
238     void noteAtomLogged(int atomId, int32_t timeSec);
239 
240     /**
241      * Report that statsd modified the anomaly alarm registered with StatsCompanionService.
242      */
243     void noteRegisteredAnomalyAlarmChanged();
244 
245     /**
246      * Report that statsd modified the periodic alarm registered with StatsCompanionService.
247      */
248     void noteRegisteredPeriodicAlarmChanged();
249 
250     /**
251      * Records the number of delta entries that are being dropped from the uid map.
252      */
253     void noteUidMapDropped(int deltas);
254 
255     /**
256      * Records that an app was deleted (from statsd's map).
257      */
258     void noteUidMapAppDeletionDropped();
259 
260     /**
261      * Updates the number of changes currently stored in the uid map.
262      */
263     void setUidMapChanges(int changes);
264     void setCurrentUidMapMemory(int bytes);
265 
266     // Update minimum interval between pulls for an pulled atom
267     void updateMinPullIntervalSec(int pullAtomId, long intervalSec);
268 
269     // Notify pull request for an atom
270     void notePull(int pullAtomId);
271 
272     // Notify pull request for an atom served from cached data
273     void notePullFromCache(int pullAtomId);
274 
275     /**
276      * Records statsd met an error while reading from logd.
277      */
278     void noteLoggerError(int error);
279 
280     /*
281     * Records when system server restarts.
282     */
283     void noteSystemServerRestart(int32_t timeSec);
284 
285     /**
286      * Records statsd skipped an event.
287      */
288     void noteLogLost(int64_t timestamp);
289 
290     /**
291      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
292      * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
293      * to collect stats after reset() has been called.
294      */
295     void reset();
296 
297     /**
298      * Output the stats in protobuf binary format to [buffer].
299      *
300      * [reset]: whether to clear the historical stats after the call.
301      */
302     void dumpStats(std::vector<uint8_t>* buffer, bool reset);
303 
304     /**
305      * Output statsd stats in human readable format to [out] file.
306      */
307     void dumpStats(FILE* out) const;
308 
309     typedef struct {
310         long totalPull;
311         long totalPullFromCache;
312         long minPullIntervalSec;
313     } PulledAtomStats;
314 
315 private:
316     StatsdStats();
317 
318     mutable std::mutex mLock;
319 
320     int32_t mStartTimeSec;
321 
322     // Track the number of dropped entries used by the uid map.
323     UidMapStats mUidMapStats;
324 
325     // The stats about the configs that are still in use.
326     // The map size is capped by kMaxConfigCount.
327     std::map<const ConfigKey, std::shared_ptr<ConfigStats>> mConfigStats;
328 
329     // Stores the stats for the configs that are no longer in use.
330     // The size of the vector is capped by kMaxIceBoxSize.
331     std::list<const std::shared_ptr<ConfigStats>> mIceBox;
332 
333     // Stores the number of times a pushed atom is logged.
334     // The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms
335     // out of that range will be dropped (it's either pulled atoms or test atoms).
336     // This is a vector, not a map because it will be accessed A LOT -- for each stats log.
337     std::vector<int> mPushedAtomStats;
338 
339     // Maps PullAtomId to its stats. The size is capped by the puller atom counts.
340     std::map<int, PulledAtomStats> mPulledAtomStats;
341 
342     // Logd errors. Size capped by kMaxLoggerErrors.
343     std::list<const std::pair<int, int>> mLoggerErrors;
344 
345     // Timestamps when we detect log loss after logd reconnect.
346     std::list<int64_t> mLogLossTimestampNs;
347 
348     std::list<int32_t> mSystemServerRestartSec;
349 
350     // Stores the number of times statsd modified the anomaly alarm registered with
351     // StatsCompanionService.
352     int mAnomalyAlarmRegisteredStats = 0;
353 
354     // Stores the number of times statsd registers the periodic alarm changes
355     int mPeriodicAlarmRegisteredStats = 0;
356 
357     void noteConfigResetInternalLocked(const ConfigKey& key);
358 
359     void noteConfigRemovedInternalLocked(const ConfigKey& key);
360 
361     void resetInternalLocked();
362 
363     void noteDataDropped(const ConfigKey& key, int32_t timeSec);
364 
365     void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes, int32_t timeSec);
366 
367     void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
368 
369     void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
370 
371     FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
372     FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
373     FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
374     FRIEND_TEST(StatsdStatsTest, TestSubStats);
375     FRIEND_TEST(StatsdStatsTest, TestAtomLog);
376     FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold);
377     FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
378     FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash);
379 };
380 
381 }  // namespace statsd
382 }  // namespace os
383 }  // namespace android
384