summaryrefslogtreecommitdiff
path: root/statsd/src/metrics/MetricsManager.h
blob: 22d5ecf1d3d5997c3beb8cc934809437539b738e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
/*
 * Copyright (C) 2017 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.
 */

#pragma once

#include <unordered_map>

#include "anomaly/AlarmMonitor.h"
#include "anomaly/AlarmTracker.h"
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionTracker.h"
#include "config/ConfigKey.h"
#include "config/ConfigMetadataProvider.h"
#include "external/StatsPullerManager.h"
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "matchers/AtomMatchingTracker.h"
#include "metrics/MetricProducer.h"
#include "packages/UidMap.h"
#include "src/statsd_config.pb.h"
#include "src/statsd_metadata.pb.h"

namespace android {
namespace os {
namespace statsd {

// A MetricsManager is responsible for managing metrics from one single config source.
class MetricsManager : public virtual RefBase,
                       public virtual PullUidProvider,
                       public virtual ConfigMetadataProvider {
public:
    MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, int64_t timeBaseNs,
                   const int64_t currentTimeNs, const sp<UidMap>& uidMap,
                   const sp<StatsPullerManager>& pullerManager,
                   const sp<AlarmMonitor>& anomalyAlarmMonitor,
                   const sp<AlarmMonitor>& periodicAlarmMonitor);

    virtual ~MetricsManager();

    bool updateConfig(const StatsdConfig& config, int64_t timeBaseNs, const int64_t currentTimeNs,
                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
                      const sp<AlarmMonitor>& periodicAlarmMonitor);

    // Return whether the configuration is valid.
    bool isConfigValid() const;

    virtual void onLogEvent(const LogEvent& event);

    void onAnomalyAlarmFired(
            int64_t timestampNs,
            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);

    void onPeriodicAlarmFired(
            int64_t timestampNs,
            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);

    void notifyAppUpgrade(int64_t eventTimeNs, const string& apk, int uid, int64_t version);

    void notifyAppRemoved(int64_t eventTimeNs, const string& apk, int uid);

    void onUidMapReceived(int64_t eventTimeNs);

    void onStatsdInitCompleted(int64_t elapsedTimeNs);

    void init();

    vector<int32_t> getPullAtomUids(int32_t atomId) override;

    bool useV2SoftMemoryCalculation() override;

    bool shouldWriteToDisk() const {
        return mNoReportMetricIds.size() != mAllMetricProducers.size();
    }

    bool shouldPersistLocalHistory() const {
        return mShouldPersistHistory;
    }

    void dumpStates(int out, bool verbose);

    inline bool isInTtl(const int64_t timestampNs) const {
        return mTtlNs <= 0 || timestampNs < mTtlEndNs;
    };

    inline bool hashStringInReport() const {
        return mHashStringsInReport;
    };

    inline bool versionStringsInReport() const {
        return mVersionStringsInReport;
    };

    inline bool installerInReport() const {
        return mInstallerInReport;
    };

    inline uint8_t packageCertificateHashSizeBytes() const {
        return mPackageCertificateHashSizeBytes;
    }

    void refreshTtl(const int64_t currentTimestampNs) {
        if (mTtlNs > 0) {
            mTtlEndNs = currentTimestampNs + mTtlNs;
        }
    };

    // Returns the elapsed realtime when this metric manager last reported metrics. If this config
    // has not yet dumped any reports, this is the time the metricsmanager was initialized.
    inline int64_t getLastReportTimeNs() const {
        return mLastReportTimeNs;
    };

    inline int64_t getLastReportWallClockNs() const {
        return mLastReportWallClockNs;
    };

    inline size_t getNumMetrics() const {
        return mAllMetricProducers.size();
    }

    virtual void dropData(const int64_t dropTimeNs);

    virtual void onDumpReport(const int64_t dumpTimeNs, int64_t wallClockNs,
                              const bool include_current_partial_bucket, const bool erase_data,
                              const DumpLatency dumpLatency, std::set<string>* str_set,
                              android::util::ProtoOutputStream* protoOutput);

    // Computes the total byte size of all metrics managed by a single config source.
    // Does not change the state.
    virtual size_t byteSize();

    // Returns whether or not this config is active.
    // The config is active if any metric in the config is active.
    inline bool isActive() const {
        return mIsActive;
    }

    void loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs);

    void writeActiveConfigToProtoOutputStream(
            int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);

    // Returns true if at least one piece of metadata is written.
    bool writeMetadataToProto(int64_t currentWallClockTimeNs,
                              int64_t systemElapsedTimeNs,
                              metadata::StatsMetadata* statsMetadata);

    void loadMetadata(const metadata::StatsMetadata& metadata,
                      int64_t currentWallClockTimeNs,
                      int64_t systemElapsedTimeNs);

    inline bool hasRestrictedMetricsDelegate() const {
        return mRestrictedMetricsDelegatePackageName.has_value();
    }

    inline string getRestrictedMetricsDelegate() const {
        return hasRestrictedMetricsDelegate() ? mRestrictedMetricsDelegatePackageName.value() : "";
    }

    inline ConfigKey getConfigKey() const {
        return mConfigKey;
    }

    void enforceRestrictedDataTtls(const int64_t wallClockNs);

    bool validateRestrictedMetricsDelegate(int32_t callingUid);

    virtual void flushRestrictedData();

    // Slow, should not be called in a hotpath.
    vector<int64_t> getAllMetricIds() const;

    // Adds all atom ids referenced by matchers in the MetricsManager's config
    void addAllAtomIds(LogEventFilter::AtomIdSet& allIds) const;

    // Gets the memory limit for the MetricsManager's config
    inline size_t getMaxMetricsBytes() const {
        return mMaxMetricsBytes;
    }

    inline size_t getTriggerGetDataBytes() const {
        return mTriggerGetDataBytes;
    }

private:
    // For test only.
    inline int64_t getTtlEndNs() const { return mTtlEndNs; }

    const ConfigKey mConfigKey;

    sp<UidMap> mUidMap;

    bool mHashStringsInReport = false;
    bool mVersionStringsInReport = false;
    bool mInstallerInReport = false;
    uint8_t mPackageCertificateHashSizeBytes;

    int64_t mTtlNs;
    int64_t mTtlEndNs;

    int64_t mLastReportTimeNs;
    int64_t mLastReportWallClockNs;

    optional<InvalidConfigReason> mInvalidConfigReason;

    sp<StatsPullerManager> mPullerManager;

    // The uid log sources from StatsdConfig.
    std::vector<int32_t> mAllowedUid;

    // The pkg log sources from StatsdConfig.
    std::vector<std::string> mAllowedPkg;

    // The combined uid sources (after translating pkg name to uid).
    // Logs from uids that are not in the list will be ignored to avoid spamming.
    std::set<int32_t> mAllowedLogSources;

    // To guard access to mAllowedLogSources
    mutable std::mutex mAllowedLogSourcesMutex;

    std::set<int32_t> mWhitelistedAtomIds;

    // We can pull any atom from these uids.
    std::set<int32_t> mDefaultPullUids;

    // Uids that specific atoms can pull from.
    // This is a map<atom id, set<uids>>
    std::map<int32_t, std::set<int32_t>> mPullAtomUids;

    // Packages that specific atoms can be pulled from.
    std::map<int32_t, std::set<std::string>> mPullAtomPackages;

    // All uids to pull for this atom. NOTE: Does not include the default uids for memory.
    std::map<int32_t, std::set<int32_t>> mCombinedPullAtomUids;

    // Contains the annotations passed in with StatsdConfig.
    std::list<std::pair<const int64_t, const int32_t>> mAnnotations;

    bool mShouldPersistHistory;
    bool mUseV2SoftMemoryCalculation;

    // All event tags that are interesting to config metrics matchers.
    std::unordered_map<int, std::vector<int>> mTagIdsToMatchersMap;

    // We only store the sp of AtomMatchingTracker, MetricProducer, and ConditionTracker in
    // MetricsManager. There are relationships between them, and the relationships are denoted by
    // index instead of pointers. The reasons for this are: (1) the relationship between them are
    // complicated, so storing index instead of pointers reduces the risk that A holds B's sp, and B
    // holds A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get
    // the related results from a cache using the index.

    // Hold all the atom matchers from the config.
    std::vector<sp<AtomMatchingTracker>> mAllAtomMatchingTrackers;

    // Hold all the conditions from the config.
    std::vector<sp<ConditionTracker>> mAllConditionTrackers;

    // Hold all metrics from the config.
    std::vector<sp<MetricProducer>> mAllMetricProducers;

    // Hold all alert trackers.
    std::vector<sp<AnomalyTracker>> mAllAnomalyTrackers;

    // Hold all periodic alarm trackers.
    std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers;

    // To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and
    // ConditionTracker to its index in the corresponding vector.

    // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers.
    std::unordered_map<int64_t, int> mAtomMatchingTrackerMap;

    // Maps the id of a condition tracker to its index in mAllConditionTrackers.
    std::unordered_map<int64_t, int> mConditionTrackerMap;

    // Maps the id of a metric producer to its index in mAllMetricProducers.
    std::unordered_map<int64_t, int> mMetricProducerMap;

    // To make the log processing more efficient, we want to do as much filtering as possible
    // before we go into individual trackers and conditions to match.

    // 1st filter: check if the event tag id is in mTagIdsToMatchersMap.
    // 2nd filter: if it is, we parse the event because there is at least one member is interested.
    //             then pass to all AtomMatchingTrackers (itself also filter events by ids).
    // 3nd filter: for AtomMatchingTrackers that matched this event, we pass this event to the
    //             ConditionTrackers and MetricProducers that use this matcher.
    // 4th filter: for ConditionTrackers that changed value due to this event, we pass
    //             new conditions to  metrics that use this condition.

    // The following map is initialized from the statsd_config.

    // Maps from the index of the AtomMatchingTracker to index of MetricProducer.
    std::unordered_map<int, std::vector<int>> mTrackerToMetricMap;

    // Maps from AtomMatchingTracker to ConditionTracker
    std::unordered_map<int, std::vector<int>> mTrackerToConditionMap;

    // Maps from ConditionTracker to MetricProducer
    std::unordered_map<int, std::vector<int>> mConditionToMetricMap;

    // Maps from life span triggering event to MetricProducers.
    std::unordered_map<int, std::vector<int>> mActivationAtomTrackerToMetricMap;

    // Maps deactivation triggering event to MetricProducers.
    std::unordered_map<int, std::vector<int>> mDeactivationAtomTrackerToMetricMap;

    // Maps AlertIds to the index of the corresponding AnomalyTracker stored in mAllAnomalyTrackers.
    // The map is used in LoadMetadata to more efficiently lookup AnomalyTrackers from an AlertId.
    std::unordered_map<int64_t, int> mAlertTrackerMap;

    std::vector<int> mMetricIndexesWithActivation;

    inline bool checkLogCredentials(const LogEvent& event) const {
        return checkLogCredentials(event.GetUid(), event.GetTagId());
    }

    bool checkLogCredentials(int32_t uid, int32_t atomId) const;

    void initAllowedLogSources();

    void initPullAtomSources();

    // Only called on config creation/update to initialize log sources from the config.
    // Calls initAllowedLogSources and initPullAtomSources. Sets up mInvalidConfigReason on
    // error.
    void createAllLogSourcesFromConfig(const StatsdConfig& config);

    // Verifies the config meets guardrails and updates statsdStats.
    // Sets up mInvalidConfigReason on error. Should be called on config creation/update
    void verifyGuardrailsAndUpdateStatsdStats();

    // Initializes mIsAlwaysActive and mIsActive.
    // Should be called on config creation/update.
    void initializeConfigActiveStatus();

    // The metrics that don't need to be uploaded or even reported.
    std::set<int64_t> mNoReportMetricIds;

   // The config is active if any metric in the config is active.
    bool mIsActive;

    // The config is always active if any metric in the config does not have an activation signal.
    bool mIsAlwaysActive;

    // Hashes of the States used in this config, keyed by the state id, used in config updates.
    std::map<int64_t, uint64_t> mStateProtoHashes;

    // Optional package name of the delegate that processes restricted metrics
    // If set, restricted metrics are only uploaded to the delegate.
    optional<string> mRestrictedMetricsDelegatePackageName = nullopt;

    // Only called on config creation/update. Sets the memory limit in bytes for storing metrics.
    void setMaxMetricsBytesFromConfig(const StatsdConfig& config);

    // Only called on config creation/update. Sets the soft memory limit in bytes for storing
    // metrics.
    void setTriggerGetDataBytesFromConfig(const StatsdConfig& config);

    void onLogEventLost(const SocketLossInfo& socketLossInfo);

    // The memory limit in bytes for storing metrics
    size_t mMaxMetricsBytes;

    // The memory limit in bytes for triggering get data.
    size_t mTriggerGetDataBytes;

    FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);

    FRIEND_TEST(GaugeMetricE2ePushedTest, TestDimensionalSampling);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestFirstNSamplesPulledNoTrigger);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestFirstNSamplesPulledNoTriggerWithActivation);
    FRIEND_TEST(GaugeMetricE2ePushedTest, TestMultipleFieldsForPushedEvent);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestRandomSamplePulledEvents);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestRandomSamplePulledEvent_LateAlarm);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestRandomSamplePulledEventsWithActivation);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestRandomSamplePulledEventsNoCondition);
    FRIEND_TEST(GaugeMetricE2ePulledTest, TestConditionChangeToTrueSamplePulledEvents);

    FRIEND_TEST(AnomalyCountDetectionE2eTest, TestSlicedCountMetric_single_bucket);
    FRIEND_TEST(AnomalyCountDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
    FRIEND_TEST(AnomalyCountDetectionE2eTest,
                TestCountMetric_save_refractory_to_disk_no_data_written);
    FRIEND_TEST(AnomalyCountDetectionE2eTest, TestCountMetric_save_refractory_to_disk);
    FRIEND_TEST(AnomalyCountDetectionE2eTest, TestCountMetric_load_refractory_from_disk);
    FRIEND_TEST(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
    FRIEND_TEST(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_partial_bucket);
    FRIEND_TEST(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
    FRIEND_TEST(AnomalyDurationDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);

    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
    FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
    FRIEND_TEST(ConfigUpdateE2eAbTest, TestConfigTtl);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);

    FRIEND_TEST(MetricsManagerTest, TestLogSources);
    FRIEND_TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom);
    FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
    FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForAllowedFromAnyUidAtom);
    FRIEND_TEST(MetricsManagerTest, TestOnLogEventLossForNotAllowedAtom);
    FRIEND_TEST(MetricsManagerTest_SPlus, TestRestrictedMetricsConfig);
    FRIEND_TEST(MetricsManagerTest_SPlus, TestRestrictedMetricsConfigUpdate);
    FRIEND_TEST(MetricsManagerUtilTest, TestSampledMetrics);

    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
    FRIEND_TEST(StatsLogProcessorTest,
            TestActivationOnBootMultipleActivationsDifferentActivationTypes);
    FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);

    FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);

    FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
    FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
    FRIEND_TEST(DurationMetricE2eTest, TestWithActivation);
    FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
    FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedState);
    FRIEND_TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState);
    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStateMapped);
    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset);
    FRIEND_TEST(DurationMetricE2eTest, TestUploadThreshold);

    FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
    FRIEND_TEST(ValueMetricE2eTest, TestInitWithMultipleAggTypes);
    FRIEND_TEST(ValueMetricE2eTest, TestInitWithDefaultAggType);
};

}  // namespace statsd
}  // namespace os
}  // namespace android