The data and activation broadcasts were guardrailed using elapsedRealtime of the *LogEvent*. However, it's possible to use incorrect timestamps, and it's also possible that we could process events that are old, which would result in the broadcast getting sent too frequently. To fix this, we should use the current elapsedRealtime instead of the LogEvent's elapsedRealtime. I can remove the config activation broadcast if we think we should hold off on it. Test: bit statsd_test:* Bug: 143155387 Change-Id: I4c58d2558d6ba3b4fd15a4a619d6f80a7bd7113f
1669 lines
72 KiB
C++
1669 lines
72 KiB
C++
// 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.
|
|
|
|
#include "StatsLogProcessor.h"
|
|
#include "StatsService.h"
|
|
#include "config/ConfigKey.h"
|
|
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
|
|
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
|
|
#include "guardrail/StatsdStats.h"
|
|
#include "logd/LogEvent.h"
|
|
#include "packages/UidMap.h"
|
|
#include "storage/StorageManager.h"
|
|
#include "statslog.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "tests/statsd_test_util.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
using namespace android;
|
|
using namespace testing;
|
|
|
|
namespace android {
|
|
namespace os {
|
|
namespace statsd {
|
|
|
|
using android::util::ProtoOutputStream;
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
/**
|
|
* Mock MetricsManager (ByteSize() is called).
|
|
*/
|
|
class MockMetricsManager : public MetricsManager {
|
|
public:
|
|
MockMetricsManager()
|
|
: MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, 1000, new UidMap(),
|
|
new StatsPullerManager(),
|
|
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t) {},
|
|
[](const sp<IStatsCompanionService>&) {}),
|
|
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t) {},
|
|
[](const sp<IStatsCompanionService>&) {})) {
|
|
}
|
|
|
|
MOCK_METHOD0(byteSize, size_t());
|
|
|
|
MOCK_METHOD1(dropData, void(const int64_t dropTimeNs));
|
|
};
|
|
|
|
TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> periodicAlarmMonitor;
|
|
// Construct the processor with a dummy sendBroadcast function that does nothing.
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
|
|
[](const ConfigKey& key) { return true; },
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
|
|
MockMetricsManager mockMetricsManager;
|
|
|
|
ConfigKey key(100, 12345);
|
|
// Expect only the first flush to trigger a check for byte size since the last two are
|
|
// rate-limited.
|
|
EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
|
|
p.flushIfNecessaryLocked(key, mockMetricsManager);
|
|
p.flushIfNecessaryLocked(key, mockMetricsManager);
|
|
p.flushIfNecessaryLocked(key, mockMetricsManager);
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
|
[&broadcastCount](const ConfigKey& key) {
|
|
broadcastCount++;
|
|
return true;
|
|
},
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
|
|
MockMetricsManager mockMetricsManager;
|
|
|
|
ConfigKey key(100, 12345);
|
|
EXPECT_CALL(mockMetricsManager, byteSize())
|
|
.Times(1)
|
|
.WillRepeatedly(::testing::Return(int(
|
|
StatsdStats::kMaxMetricsBytesPerConfig * .95)));
|
|
|
|
// Expect only one broadcast despite always returning a size that should trigger broadcast.
|
|
p.flushIfNecessaryLocked(key, mockMetricsManager);
|
|
EXPECT_EQ(1, broadcastCount);
|
|
|
|
// b/73089712
|
|
// This next call to flush should not trigger a broadcast.
|
|
// p.mLastByteSizeTimes.clear(); // Force another check for byte size.
|
|
// p.flushIfNecessaryLocked(2, key, mockMetricsManager);
|
|
// EXPECT_EQ(1, broadcastCount);
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
|
[&broadcastCount](const ConfigKey& key) {
|
|
broadcastCount++;
|
|
return true;
|
|
},
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
|
|
MockMetricsManager mockMetricsManager;
|
|
|
|
ConfigKey key(100, 12345);
|
|
EXPECT_CALL(mockMetricsManager, byteSize())
|
|
.Times(1)
|
|
.WillRepeatedly(::testing::Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
|
|
|
|
EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1);
|
|
|
|
// Expect to call the onDumpReport and skip the broadcast.
|
|
p.flushIfNecessaryLocked(key, mockMetricsManager);
|
|
EXPECT_EQ(0, broadcastCount);
|
|
}
|
|
|
|
StatsdConfig MakeConfig(bool includeMetric) {
|
|
StatsdConfig config;
|
|
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
|
|
if (includeMetric) {
|
|
auto appCrashMatcher = CreateProcessCrashAtomMatcher();
|
|
*config.add_atom_matcher() = appCrashMatcher;
|
|
auto countMetric = config.add_count_metric();
|
|
countMetric->set_id(StringToId("AppCrashes"));
|
|
countMetric->set_what(appCrashMatcher.id());
|
|
countMetric->set_bucket(FIVE_MINUTES);
|
|
}
|
|
return config;
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
|
|
// Setup simple config key corresponding to empty config.
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
|
|
{String16("p1"), String16("p2")}, {String16(""), String16("")});
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
|
[&broadcastCount](const ConfigKey& key) {
|
|
broadcastCount++;
|
|
return true;
|
|
},
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
ConfigKey key(3, 4);
|
|
StatsdConfig config = MakeConfig(true);
|
|
p.OnConfigUpdated(0, key, config);
|
|
|
|
// Expect to get no metrics, but snapshot specified above in uidmap.
|
|
vector<uint8_t> bytes;
|
|
p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
|
|
|
|
ConfigMetricsReportList output;
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
EXPECT_TRUE(output.reports_size() > 0);
|
|
auto uidmap = output.reports(0).uid_map();
|
|
EXPECT_TRUE(uidmap.snapshots_size() > 0);
|
|
EXPECT_EQ(2, uidmap.snapshots(0).package_info_size());
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
|
|
// Setup simple config key corresponding to empty config.
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
|
|
{String16("p1"), String16("p2")}, {String16(""), String16("")});
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
|
[&broadcastCount](const ConfigKey& key) {
|
|
broadcastCount++;
|
|
return true;
|
|
},
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
ConfigKey key(3, 4);
|
|
StatsdConfig config = MakeConfig(false);
|
|
p.OnConfigUpdated(0, key, config);
|
|
|
|
// Expect to get no metrics, but snapshot specified above in uidmap.
|
|
vector<uint8_t> bytes;
|
|
p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
|
|
|
|
ConfigMetricsReportList output;
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
EXPECT_TRUE(output.reports_size() > 0);
|
|
EXPECT_FALSE(output.reports(0).has_uid_map());
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
|
|
// Setup simple config key corresponding to empty config.
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
|
|
[&broadcastCount](const ConfigKey& key) {
|
|
broadcastCount++;
|
|
return true;
|
|
},
|
|
[](const int&, const vector<int64_t>&) {return true;});
|
|
ConfigKey key(3, 4);
|
|
StatsdConfig config;
|
|
auto annotation = config.add_annotation();
|
|
annotation->set_field_int64(1);
|
|
annotation->set_field_int32(2);
|
|
config.add_allowed_log_source("AID_ROOT");
|
|
p.OnConfigUpdated(1, key, config);
|
|
|
|
// Expect to get no metrics, but snapshot specified above in uidmap.
|
|
vector<uint8_t> bytes;
|
|
p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
|
|
|
|
ConfigMetricsReportList output;
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
EXPECT_TRUE(output.reports_size() > 0);
|
|
auto report = output.reports(0);
|
|
EXPECT_EQ(1, report.annotation_size());
|
|
EXPECT_EQ(1, report.annotation(0).field_int64());
|
|
EXPECT_EQ(2, report.annotation(0).field_int32());
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestOnDumpReportEraseData) {
|
|
// Setup a simple config.
|
|
StatsdConfig config;
|
|
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
*config.add_atom_matcher() = wakelockAcquireMatcher;
|
|
|
|
auto countMetric = config.add_count_metric();
|
|
countMetric->set_id(123456);
|
|
countMetric->set_what(wakelockAcquireMatcher.id());
|
|
countMetric->set_bucket(FIVE_MINUTES);
|
|
|
|
ConfigKey cfgKey;
|
|
sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
|
|
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 2);
|
|
processor->OnLogEvent(event.get());
|
|
|
|
vector<uint8_t> bytes;
|
|
ConfigMetricsReportList output;
|
|
|
|
// Dump report WITHOUT erasing data.
|
|
processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST, &bytes);
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
EXPECT_EQ(output.reports_size(), 1);
|
|
EXPECT_EQ(output.reports(0).metrics_size(), 1);
|
|
EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
|
|
|
|
// Dump report WITH erasing data. There should be data since we didn't previously erase it.
|
|
processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
EXPECT_EQ(output.reports_size(), 1);
|
|
EXPECT_EQ(output.reports(0).metrics_size(), 1);
|
|
EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
|
|
|
|
// Dump report again. There should be no data since we erased it.
|
|
processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
|
|
output.ParseFromArray(bytes.data(), bytes.size());
|
|
// We don't care whether statsd has a report, as long as it has no count metrics in it.
|
|
bool noData = output.reports_size() == 0
|
|
|| output.reports(0).metrics_size() == 0
|
|
|| output.reports(0).metrics(0).count_metrics().data_size() == 0;
|
|
EXPECT_TRUE(noData);
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
|
|
int uid = 1111;
|
|
|
|
// Setup a simple config, no activation
|
|
StatsdConfig config1;
|
|
int64_t cfgId1 = 12341;
|
|
config1.set_id(cfgId1);
|
|
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
*config1.add_atom_matcher() = wakelockAcquireMatcher;
|
|
|
|
long metricId1 = 1234561;
|
|
long metricId2 = 1234562;
|
|
auto countMetric1 = config1.add_count_metric();
|
|
countMetric1->set_id(metricId1);
|
|
countMetric1->set_what(wakelockAcquireMatcher.id());
|
|
countMetric1->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric2 = config1.add_count_metric();
|
|
countMetric2->set_id(metricId2);
|
|
countMetric2->set_what(wakelockAcquireMatcher.id());
|
|
countMetric2->set_bucket(FIVE_MINUTES);
|
|
|
|
ConfigKey cfgKey1(uid, cfgId1);
|
|
|
|
// Add another config, with two metrics, one with activation
|
|
StatsdConfig config2;
|
|
int64_t cfgId2 = 12342;
|
|
config2.set_id(cfgId2);
|
|
config2.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
*config2.add_atom_matcher() = wakelockAcquireMatcher;
|
|
|
|
long metricId3 = 1234561;
|
|
long metricId4 = 1234562;
|
|
|
|
auto countMetric3 = config2.add_count_metric();
|
|
countMetric3->set_id(metricId3);
|
|
countMetric3->set_what(wakelockAcquireMatcher.id());
|
|
countMetric3->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric4 = config2.add_count_metric();
|
|
countMetric4->set_id(metricId4);
|
|
countMetric4->set_what(wakelockAcquireMatcher.id());
|
|
countMetric4->set_bucket(FIVE_MINUTES);
|
|
|
|
auto metric3Activation = config2.add_metric_activation();
|
|
metric3Activation->set_metric_id(metricId3);
|
|
metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
auto metric3ActivationTrigger = metric3Activation->add_event_activation();
|
|
metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric3ActivationTrigger->set_ttl_seconds(100);
|
|
|
|
ConfigKey cfgKey2(uid, cfgId2);
|
|
|
|
// Add another config, with two metrics, both with activations
|
|
StatsdConfig config3;
|
|
int64_t cfgId3 = 12343;
|
|
config3.set_id(cfgId3);
|
|
config3.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
*config3.add_atom_matcher() = wakelockAcquireMatcher;
|
|
|
|
long metricId5 = 1234565;
|
|
long metricId6 = 1234566;
|
|
auto countMetric5 = config3.add_count_metric();
|
|
countMetric5->set_id(metricId5);
|
|
countMetric5->set_what(wakelockAcquireMatcher.id());
|
|
countMetric5->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric6 = config3.add_count_metric();
|
|
countMetric6->set_id(metricId6);
|
|
countMetric6->set_what(wakelockAcquireMatcher.id());
|
|
countMetric6->set_bucket(FIVE_MINUTES);
|
|
|
|
auto metric5Activation = config3.add_metric_activation();
|
|
metric5Activation->set_metric_id(metricId5);
|
|
metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
auto metric5ActivationTrigger = metric5Activation->add_event_activation();
|
|
metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric5ActivationTrigger->set_ttl_seconds(100);
|
|
|
|
auto metric6Activation = config3.add_metric_activation();
|
|
metric6Activation->set_metric_id(metricId6);
|
|
metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
auto metric6ActivationTrigger = metric6Activation->add_event_activation();
|
|
metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric6ActivationTrigger->set_ttl_seconds(200);
|
|
|
|
ConfigKey cfgKey3(uid, cfgId3);
|
|
|
|
sp<UidMap> m = new UidMap();
|
|
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
|
|
sp<AlarmMonitor> anomalyAlarmMonitor;
|
|
sp<AlarmMonitor> subscriberAlarmMonitor;
|
|
vector<int64_t> activeConfigsBroadcast;
|
|
|
|
long timeBase1 = 1;
|
|
int broadcastCount = 0;
|
|
StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
|
|
timeBase1, [](const ConfigKey& key) { return true; },
|
|
[&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
|
|
const vector<int64_t>& activeConfigs) {
|
|
broadcastCount++;
|
|
EXPECT_EQ(broadcastUid, uid);
|
|
activeConfigsBroadcast.clear();
|
|
activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
|
|
activeConfigs.begin(), activeConfigs.end());
|
|
return true;
|
|
});
|
|
|
|
processor.OnConfigUpdated(1, cfgKey1, config1);
|
|
processor.OnConfigUpdated(2, cfgKey2, config2);
|
|
processor.OnConfigUpdated(3, cfgKey3, config3);
|
|
|
|
EXPECT_EQ(3, processor.mMetricsManagers.size());
|
|
|
|
// Expect the first config and both metrics in it to be active.
|
|
auto it = processor.mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor.mMetricsManagers.end());
|
|
auto& metricsManager1 = it->second;
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
|
|
auto metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer1 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1->isActive());
|
|
|
|
metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer2 = *metricIt;
|
|
EXPECT_TRUE(metricProducer2->isActive());
|
|
|
|
// Expect config 2 to be active. Metric 3 shouldn't be active, metric 4 should be active.
|
|
it = processor.mMetricsManagers.find(cfgKey2);
|
|
EXPECT_TRUE(it != processor.mMetricsManagers.end());
|
|
auto& metricsManager2 = it->second;
|
|
EXPECT_TRUE(metricsManager2->isActive());
|
|
|
|
metricIt = metricsManager2->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId3) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
|
|
auto& metricProducer3 = *metricIt;
|
|
EXPECT_FALSE(metricProducer3->isActive());
|
|
|
|
metricIt = metricsManager2->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId4) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
|
|
auto& metricProducer4 = *metricIt;
|
|
EXPECT_TRUE(metricProducer4->isActive());
|
|
|
|
// Expect the third config and both metrics in it to be inactive.
|
|
it = processor.mMetricsManagers.find(cfgKey3);
|
|
EXPECT_TRUE(it != processor.mMetricsManagers.end());
|
|
auto& metricsManager3 = it->second;
|
|
EXPECT_FALSE(metricsManager3->isActive());
|
|
|
|
metricIt = metricsManager3->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId5) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
|
|
auto& metricProducer5 = *metricIt;
|
|
EXPECT_FALSE(metricProducer5->isActive());
|
|
|
|
metricIt = metricsManager3->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId6) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
|
|
auto& metricProducer6 = *metricIt;
|
|
EXPECT_FALSE(metricProducer6->isActive());
|
|
|
|
// No broadcast for active configs should have happened yet.
|
|
EXPECT_EQ(broadcastCount, 0);
|
|
|
|
// Activate all 3 metrics that were not active.
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
|
|
processor.OnLogEvent(event.get());
|
|
|
|
// Assert that all 3 configs are active.
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
EXPECT_TRUE(metricsManager2->isActive());
|
|
EXPECT_TRUE(metricsManager3->isActive());
|
|
|
|
// A broadcast should have happened, and all 3 configs should be active in the broadcast.
|
|
EXPECT_EQ(broadcastCount, 1);
|
|
EXPECT_EQ(activeConfigsBroadcast.size(), 3);
|
|
EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1)
|
|
!= activeConfigsBroadcast.end());
|
|
EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2)
|
|
!= activeConfigsBroadcast.end());
|
|
EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId3)
|
|
!= activeConfigsBroadcast.end());
|
|
|
|
// When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns.
|
|
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
|
|
processor.SaveActiveConfigsToDisk(shutDownTime);
|
|
const int64_t ttl3 = event->GetElapsedTimestampNs() +
|
|
metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
|
|
const int64_t ttl5 = event->GetElapsedTimestampNs() +
|
|
metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
|
|
const int64_t ttl6 = event->GetElapsedTimestampNs() +
|
|
metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
|
|
|
|
// Create a second StatsLogProcessor and push the same 3 configs.
|
|
long timeBase2 = 1000;
|
|
sp<StatsLogProcessor> processor2 =
|
|
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
|
|
processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
|
|
processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
|
|
|
|
EXPECT_EQ(3, processor2->mMetricsManagers.size());
|
|
|
|
// First config and both metrics are active.
|
|
it = processor2->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager1001 = it->second;
|
|
EXPECT_TRUE(metricsManager1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1001 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1002 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
|
|
// Second config is active. Metric 3 is inactive, metric 4 is active.
|
|
it = processor2->mMetricsManagers.find(cfgKey2);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager1002 = it->second;
|
|
EXPECT_TRUE(metricsManager1002->isActive());
|
|
|
|
metricIt = metricsManager1002->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId3) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
|
|
auto& metricProducer1003 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1003->isActive());
|
|
|
|
metricIt = metricsManager1002->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId4) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
|
|
auto& metricProducer1004 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1004->isActive());
|
|
|
|
// Config 3 is inactive. both metrics are inactive.
|
|
it = processor2->mMetricsManagers.find(cfgKey3);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager1003 = it->second;
|
|
EXPECT_FALSE(metricsManager1003->isActive());
|
|
EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size());
|
|
|
|
metricIt = metricsManager1003->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId5) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
|
|
auto& metricProducer1005 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1005->isActive());
|
|
|
|
metricIt = metricsManager1003->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId6) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
|
|
auto& metricProducer1006 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1006->isActive());
|
|
|
|
// Assert that all 3 metrics with activation are inactive and that the ttls were properly set.
|
|
EXPECT_FALSE(metricProducer1003->isActive());
|
|
const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
|
|
EXPECT_EQ(0, activation1003->start_ns);
|
|
EXPECT_FALSE(metricProducer1005->isActive());
|
|
const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns);
|
|
EXPECT_EQ(0, activation1005->start_ns);
|
|
EXPECT_FALSE(metricProducer1006->isActive());
|
|
const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns);
|
|
EXPECT_EQ(0, activation1006->start_ns);
|
|
|
|
processor2->LoadActiveConfigsFromDisk();
|
|
|
|
// After loading activations from disk, assert that all 3 metrics are active.
|
|
EXPECT_TRUE(metricProducer1003->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
|
|
EXPECT_TRUE(metricProducer1005->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
|
|
EXPECT_TRUE(metricProducer1006->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
|
|
|
|
// Make sure no more broadcasts have happened.
|
|
EXPECT_EQ(broadcastCount, 1);
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestActivationOnBoot) {
|
|
int uid = 1111;
|
|
|
|
StatsdConfig config1;
|
|
config1.set_id(12341);
|
|
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
*config1.add_atom_matcher() = wakelockAcquireMatcher;
|
|
|
|
long metricId1 = 1234561;
|
|
long metricId2 = 1234562;
|
|
auto countMetric1 = config1.add_count_metric();
|
|
countMetric1->set_id(metricId1);
|
|
countMetric1->set_what(wakelockAcquireMatcher.id());
|
|
countMetric1->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric2 = config1.add_count_metric();
|
|
countMetric2->set_id(metricId2);
|
|
countMetric2->set_what(wakelockAcquireMatcher.id());
|
|
countMetric2->set_bucket(FIVE_MINUTES);
|
|
|
|
auto metric1Activation = config1.add_metric_activation();
|
|
metric1Activation->set_metric_id(metricId1);
|
|
metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
|
|
auto metric1ActivationTrigger = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric1ActivationTrigger->set_ttl_seconds(100);
|
|
|
|
ConfigKey cfgKey1(uid, 12341);
|
|
long timeBase1 = 1;
|
|
sp<StatsLogProcessor> processor =
|
|
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
|
|
|
|
EXPECT_EQ(1, processor->mMetricsManagers.size());
|
|
auto it = processor->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor->mMetricsManagers.end());
|
|
auto& metricsManager1 = it->second;
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
|
|
auto metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer1 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
|
|
metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer2 = *metricIt;
|
|
EXPECT_TRUE(metricProducer2->isActive());
|
|
|
|
const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1->state);
|
|
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
|
|
processor->OnLogEvent(event.get());
|
|
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1->state);
|
|
|
|
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
|
|
processor->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
|
|
|
|
long timeBase2 = 1000;
|
|
sp<StatsLogProcessor> processor2 =
|
|
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
|
|
|
|
EXPECT_EQ(1, processor2->mMetricsManagers.size());
|
|
it = processor2->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager1001 = it->second;
|
|
EXPECT_TRUE(metricsManager1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1001 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1002 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
|
|
const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
|
|
EXPECT_EQ(0, activation1001->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1001->state);
|
|
|
|
processor2->LoadActiveConfigsFromDisk();
|
|
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
|
|
EXPECT_EQ(kActive, activation1001->state);
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
|
|
int uid = 1111;
|
|
|
|
// Create config with 2 metrics:
|
|
// Metric 1: Activate on boot with 2 activations
|
|
// Metric 2: Always active
|
|
StatsdConfig config1;
|
|
config1.set_id(12341);
|
|
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
|
|
*config1.add_atom_matcher() = wakelockAcquireMatcher;
|
|
*config1.add_atom_matcher() = screenOnMatcher;
|
|
|
|
long metricId1 = 1234561;
|
|
long metricId2 = 1234562;
|
|
|
|
auto countMetric1 = config1.add_count_metric();
|
|
countMetric1->set_id(metricId1);
|
|
countMetric1->set_what(wakelockAcquireMatcher.id());
|
|
countMetric1->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric2 = config1.add_count_metric();
|
|
countMetric2->set_id(metricId2);
|
|
countMetric2->set_what(wakelockAcquireMatcher.id());
|
|
countMetric2->set_bucket(FIVE_MINUTES);
|
|
|
|
auto metric1Activation = config1.add_metric_activation();
|
|
metric1Activation->set_metric_id(metricId1);
|
|
metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
|
|
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric1ActivationTrigger1->set_ttl_seconds(100);
|
|
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
|
|
metric1ActivationTrigger2->set_ttl_seconds(200);
|
|
|
|
ConfigKey cfgKey1(uid, 12341);
|
|
long timeBase1 = 1;
|
|
sp<StatsLogProcessor> processor =
|
|
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor->mMetricsManagers.size());
|
|
auto it = processor->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor->mMetricsManagers.end());
|
|
auto& metricsManager1 = it->second;
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
|
|
auto metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer1 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
|
|
metricIt = metricsManager1->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
|
|
auto& metricProducer2 = *metricIt;
|
|
EXPECT_TRUE(metricProducer2->isActive());
|
|
|
|
int i = 0;
|
|
for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManager1->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger1->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1->state);
|
|
|
|
i = 0;
|
|
for (; i < metricsManager1->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManager1->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger2->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
|
|
EXPECT_EQ(0, activation2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2->state);
|
|
// }}}------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 1 for Metric 1
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
|
|
processor->OnLogEvent(event.get());
|
|
|
|
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1->state);
|
|
EXPECT_EQ(0, activation2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2->state);
|
|
|
|
EXPECT_TRUE(metricProducer2->isActive());
|
|
// }}}-----------------------------------------------------------------------------
|
|
|
|
// Simulate shutdown by saving state to disk
|
|
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
|
|
processor->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
|
|
|
|
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
|
|
// same config.
|
|
long timeBase2 = 1000;
|
|
sp<StatsLogProcessor> processor2 =
|
|
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor2->mMetricsManagers.size());
|
|
it = processor2->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager1001 = it->second;
|
|
EXPECT_TRUE(metricsManager1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1001 = *metricIt;
|
|
EXPECT_FALSE(metricProducer1001->isActive());
|
|
|
|
metricIt = metricsManager1001->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
|
|
auto& metricProducer1002 = *metricIt;
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
|
|
i = 0;
|
|
for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger1->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
|
|
EXPECT_EQ(0, activation1001_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1001_1->state);
|
|
|
|
i = 0;
|
|
for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManager1001->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger2->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
|
|
EXPECT_EQ(0, activation1001_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1001_2->state);
|
|
// }}}-----------------------------------------------------------------------------------
|
|
|
|
// Load saved state from disk.
|
|
processor2->LoadActiveConfigsFromDisk();
|
|
|
|
// Metric 1 active; Activation 1 is active, Activation 2 is not active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
|
|
EXPECT_EQ(kActive, activation1001_1->state);
|
|
EXPECT_EQ(0, activation1001_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1001_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
// }}}--------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 2 for Metric 1.
|
|
auto screenOnEvent = CreateScreenStateChangedEvent(
|
|
android::view::DISPLAY_STATE_ON,
|
|
timeBase2 + 200
|
|
);
|
|
processor2->OnLogEvent(screenOnEvent.get());
|
|
|
|
// Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
|
|
EXPECT_EQ(kActive, activation1001_1->state);
|
|
EXPECT_EQ(0, activation1001_2->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
// }}}---------------------------------------------------------------------------
|
|
|
|
// Simulate shutdown by saving state to disk
|
|
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
|
|
processor2->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
|
|
int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
|
|
|
|
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
|
|
// same config.
|
|
long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
|
|
sp<StatsLogProcessor> processor3 =
|
|
CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor3->mMetricsManagers.size());
|
|
it = processor3->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
|
|
auto& metricsManagerTimeBase3 = it->second;
|
|
EXPECT_TRUE(metricsManagerTimeBase3->isActive());
|
|
|
|
metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
|
|
auto& metricProducerTimeBase3_1 = *metricIt;
|
|
EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
|
|
|
|
metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
|
|
auto& metricProducerTimeBase3_2 = *metricIt;
|
|
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
|
|
|
|
i = 0;
|
|
for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger1->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
|
|
EXPECT_EQ(0, activationTimeBase3_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
|
|
|
|
i = 0;
|
|
for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger2->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
|
|
EXPECT_EQ(0, activationTimeBase3_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
|
|
|
|
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
|
|
// }}}----------------------------------------------------------------------------------
|
|
|
|
// Load saved state from disk.
|
|
processor3->LoadActiveConfigsFromDisk();
|
|
|
|
// Metric 1 active: Activation 1 is active, Activation 2 is active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
|
|
EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
|
|
EXPECT_EQ(kActive, activationTimeBase3_1->state);
|
|
EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
|
|
EXPECT_EQ(kActive, activationTimeBase3_2->state);
|
|
|
|
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
|
|
// }}}-------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 2 for Metric 1 again.
|
|
screenOnEvent = CreateScreenStateChangedEvent(
|
|
android::view::DISPLAY_STATE_ON,
|
|
timeBase3 + 100 * NS_PER_SEC
|
|
);
|
|
processor3->OnLogEvent(screenOnEvent.get());
|
|
|
|
// Metric 1 active; Activation 1 is not active, Activation 2 is set to active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
|
|
EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
|
|
EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
|
|
EXPECT_EQ(kActive, activationTimeBase3_2->state);
|
|
|
|
EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
|
|
// }}}---------------------------------------------------------------------------
|
|
|
|
// Simulate shutdown by saving state to disk.
|
|
shutDownTime = timeBase3 + 500 * NS_PER_SEC;
|
|
processor3->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_TRUE(metricProducer1001->isActive());
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
ttl1 = timeBase3 + ttl1 - shutDownTime;
|
|
ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
|
|
|
|
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
|
|
// same config.
|
|
long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
|
|
sp<StatsLogProcessor> processor4 =
|
|
CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor4->mMetricsManagers.size());
|
|
it = processor4->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor4->mMetricsManagers.end());
|
|
auto& metricsManagerTimeBase4 = it->second;
|
|
EXPECT_TRUE(metricsManagerTimeBase4->isActive());
|
|
|
|
metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId1) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
|
|
auto& metricProducerTimeBase4_1 = *metricIt;
|
|
EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
|
|
|
|
metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
|
|
for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
|
|
if ((*metricIt)->getMetricId() == metricId2) {
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
|
|
auto& metricProducerTimeBase4_2 = *metricIt;
|
|
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
|
|
|
|
i = 0;
|
|
for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger1->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
|
|
EXPECT_EQ(0, activationTimeBase4_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
|
|
|
|
i = 0;
|
|
for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) {
|
|
if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() ==
|
|
metric1ActivationTrigger2->atom_matcher_id()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
|
|
EXPECT_EQ(0, activationTimeBase4_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
|
|
|
|
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
|
|
// }}}----------------------------------------------------------------------------------
|
|
|
|
// Load saved state from disk.
|
|
processor4->LoadActiveConfigsFromDisk();
|
|
|
|
// Metric 1 active: Activation 1 is not active, Activation 2 is not active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
|
|
EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
|
|
EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
|
|
|
|
EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
|
|
// }}}-------------------------------------------------------------------------------
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
|
|
int uid = 1111;
|
|
|
|
// Create config with 2 metrics:
|
|
// Metric 1: Activate on boot with 2 activations
|
|
// Metric 2: Always active
|
|
StatsdConfig config1;
|
|
config1.set_id(12341);
|
|
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
|
|
*config1.add_atom_matcher() = wakelockAcquireMatcher;
|
|
*config1.add_atom_matcher() = screenOnMatcher;
|
|
|
|
long metricId1 = 1234561;
|
|
long metricId2 = 1234562;
|
|
|
|
auto countMetric1 = config1.add_count_metric();
|
|
countMetric1->set_id(metricId1);
|
|
countMetric1->set_what(wakelockAcquireMatcher.id());
|
|
countMetric1->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric2 = config1.add_count_metric();
|
|
countMetric2->set_id(metricId2);
|
|
countMetric2->set_what(wakelockAcquireMatcher.id());
|
|
countMetric2->set_bucket(FIVE_MINUTES);
|
|
|
|
auto metric1Activation = config1.add_metric_activation();
|
|
metric1Activation->set_metric_id(metricId1);
|
|
metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
|
|
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric1ActivationTrigger1->set_ttl_seconds(100);
|
|
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
|
|
metric1ActivationTrigger2->set_ttl_seconds(200);
|
|
metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
|
|
ConfigKey cfgKey1(uid, 12341);
|
|
long timeBase1 = 1;
|
|
sp<StatsLogProcessor> processor1 =
|
|
CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor1->mMetricsManagers.size());
|
|
auto it = processor1->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor1->mMetricsManagers.end());
|
|
auto& metricsManager1 = it->second;
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
|
|
EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
|
|
// We assume that the index of a MetricProducer within the mAllMetricProducers
|
|
// array follows the order in which metrics are added to the config.
|
|
auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
|
|
EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
|
|
EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation
|
|
|
|
auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
|
|
EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
|
|
EXPECT_TRUE(metricProducer1_2->isActive());
|
|
|
|
EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
|
|
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
|
|
// that matchers are indexed in the order that they are added to the config.
|
|
const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
|
|
EXPECT_EQ(0, activation1_1_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1_1_1->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
|
|
|
|
const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
|
|
EXPECT_EQ(0, activation1_1_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1_1_2->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
|
|
// }}}------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 1 for Metric 1
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
|
|
processor1->OnLogEvent(event.get());
|
|
|
|
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_FALSE(metricProducer1_1->isActive());
|
|
EXPECT_EQ(0, activation1_1_1->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
|
|
EXPECT_EQ(0, activation1_1_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1_1_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer1_2->isActive());
|
|
// }}}-----------------------------------------------------------------------------
|
|
|
|
// Simulate shutdown by saving state to disk
|
|
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
|
|
processor1->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_FALSE(metricProducer1_1->isActive());
|
|
|
|
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
|
|
// same config.
|
|
long timeBase2 = 1000;
|
|
sp<StatsLogProcessor> processor2 =
|
|
CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor2->mMetricsManagers.size());
|
|
it = processor2->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor2->mMetricsManagers.end());
|
|
auto& metricsManager2 = it->second;
|
|
EXPECT_TRUE(metricsManager2->isActive());
|
|
|
|
EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
|
|
// We assume that the index of a MetricProducer within the mAllMetricProducers
|
|
// array follows the order in which metrics are added to the config.
|
|
auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
|
|
EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
|
|
EXPECT_FALSE(metricProducer2_1->isActive());
|
|
|
|
auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
|
|
EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
|
|
EXPECT_TRUE(metricProducer2_2->isActive());
|
|
|
|
EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
|
|
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
|
|
// that matchers are indexed in the order that they are added to the config.
|
|
const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
|
|
EXPECT_EQ(0, activation2_1_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2_1_1->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
|
|
|
|
const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
|
|
EXPECT_EQ(0, activation2_1_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2_1_2->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
|
|
// }}}-----------------------------------------------------------------------------------
|
|
|
|
// Load saved state from disk.
|
|
processor2->LoadActiveConfigsFromDisk();
|
|
|
|
// Metric 1 active; Activation 1 is active, Activation 2 is not active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer2_1->isActive());
|
|
int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
|
|
EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
|
|
EXPECT_EQ(kActive, activation2_1_1->state);
|
|
EXPECT_EQ(0, activation2_1_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2_1_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer2_2->isActive());
|
|
// }}}--------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 2 for Metric 1.
|
|
auto screenOnEvent = CreateScreenStateChangedEvent(
|
|
android::view::DISPLAY_STATE_ON,
|
|
timeBase2 + 200
|
|
);
|
|
processor2->OnLogEvent(screenOnEvent.get());
|
|
|
|
// Metric 1 active; Activation 1 is active, Activation 2 is active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer2_1->isActive());
|
|
EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
|
|
EXPECT_EQ(kActive, activation2_1_1->state);
|
|
EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
|
|
EXPECT_EQ(kActive, activation2_1_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer2_2->isActive());
|
|
// }}}---------------------------------------------------------------------------
|
|
|
|
// Simulate shutdown by saving state to disk
|
|
shutDownTime = timeBase2 + 50 * NS_PER_SEC;
|
|
processor2->SaveActiveConfigsToDisk(shutDownTime);
|
|
EXPECT_TRUE(metricProducer2_1->isActive());
|
|
EXPECT_TRUE(metricProducer2_2->isActive());
|
|
ttl1 -= shutDownTime - timeBase2;
|
|
int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC
|
|
- (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
|
|
|
|
// Simulate device restarted state by creating new instance of StatsLogProcessor with the
|
|
// same config.
|
|
long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
|
|
sp<StatsLogProcessor> processor3 =
|
|
CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor3->mMetricsManagers.size());
|
|
it = processor3->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor3->mMetricsManagers.end());
|
|
auto& metricsManager3 = it->second;
|
|
EXPECT_TRUE(metricsManager3->isActive());
|
|
|
|
EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
|
|
// We assume that the index of a MetricProducer within the mAllMetricProducers
|
|
// array follows the order in which metrics are added to the config.
|
|
auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
|
|
EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
|
|
EXPECT_FALSE(metricProducer3_1->isActive());
|
|
|
|
auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
|
|
EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
|
|
EXPECT_TRUE(metricProducer3_2->isActive());
|
|
|
|
EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
|
|
// The key in mEventActivationMap is the index of the associated atom matcher. We assume
|
|
// that matchers are indexed in the order that they are added to the config.
|
|
const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
|
|
EXPECT_EQ(0, activation3_1_1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation3_1_1->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
|
|
|
|
const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
|
|
EXPECT_EQ(0, activation3_1_2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation3_1_2->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
|
|
// }}}----------------------------------------------------------------------------------
|
|
|
|
// Load saved state from disk.
|
|
processor3->LoadActiveConfigsFromDisk();
|
|
|
|
// Metric 1 active: Activation 1 is active, Activation 2 is active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer3_1->isActive());
|
|
EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
|
|
EXPECT_EQ(kActive, activation3_1_1->state);
|
|
EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
|
|
EXPECT_EQ(kActive, activation3_1_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer3_2->isActive());
|
|
// }}}-------------------------------------------------------------------------------
|
|
|
|
|
|
// Trigger Activation 2 for Metric 1 again.
|
|
screenOnEvent = CreateScreenStateChangedEvent(
|
|
android::view::DISPLAY_STATE_ON,
|
|
timeBase3 + 100 * NS_PER_SEC
|
|
);
|
|
processor3->OnLogEvent(screenOnEvent.get());
|
|
|
|
// Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
|
|
// Activation 2 is set to active
|
|
// Metric 2 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_TRUE(metricProducer3_1->isActive());
|
|
EXPECT_EQ(kNotActive, activation3_1_1->state);
|
|
EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
|
|
EXPECT_EQ(kActive, activation3_1_2->state);
|
|
|
|
EXPECT_TRUE(metricProducer3_2->isActive());
|
|
// }}}---------------------------------------------------------------------------
|
|
}
|
|
|
|
TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
|
|
int uid = 9876;
|
|
long configId = 12341;
|
|
|
|
// Create config with 3 metrics:
|
|
// Metric 1: Activate on 2 activations, 1 on boot, 1 immediate.
|
|
// Metric 2: Activate on 2 activations, 1 on boot, 1 immediate.
|
|
// Metric 3: Always active
|
|
StatsdConfig config1;
|
|
config1.set_id(configId);
|
|
config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
|
|
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
|
|
auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
|
|
auto jobStartMatcher = CreateStartScheduledJobAtomMatcher();
|
|
auto jobFinishMatcher = CreateFinishScheduledJobAtomMatcher();
|
|
*config1.add_atom_matcher() = wakelockAcquireMatcher;
|
|
*config1.add_atom_matcher() = screenOnMatcher;
|
|
*config1.add_atom_matcher() = jobStartMatcher;
|
|
*config1.add_atom_matcher() = jobFinishMatcher;
|
|
|
|
long metricId1 = 1234561;
|
|
long metricId2 = 1234562;
|
|
long metricId3 = 1234563;
|
|
|
|
auto countMetric1 = config1.add_count_metric();
|
|
countMetric1->set_id(metricId1);
|
|
countMetric1->set_what(wakelockAcquireMatcher.id());
|
|
countMetric1->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric2 = config1.add_count_metric();
|
|
countMetric2->set_id(metricId2);
|
|
countMetric2->set_what(wakelockAcquireMatcher.id());
|
|
countMetric2->set_bucket(FIVE_MINUTES);
|
|
|
|
auto countMetric3 = config1.add_count_metric();
|
|
countMetric3->set_id(metricId3);
|
|
countMetric3->set_what(wakelockAcquireMatcher.id());
|
|
countMetric3->set_bucket(FIVE_MINUTES);
|
|
|
|
// Metric 1 activates on boot for wakelock acquire, immediately for screen on.
|
|
auto metric1Activation = config1.add_metric_activation();
|
|
metric1Activation->set_metric_id(metricId1);
|
|
auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
|
|
metric1ActivationTrigger1->set_ttl_seconds(100);
|
|
metric1ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
|
|
auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
|
|
metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
|
|
metric1ActivationTrigger2->set_ttl_seconds(200);
|
|
metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
|
|
// Metric 2 activates on boot for scheduled job start, immediately for scheduled job finish.
|
|
auto metric2Activation = config1.add_metric_activation();
|
|
metric2Activation->set_metric_id(metricId2);
|
|
auto metric2ActivationTrigger1 = metric2Activation->add_event_activation();
|
|
metric2ActivationTrigger1->set_atom_matcher_id(jobStartMatcher.id());
|
|
metric2ActivationTrigger1->set_ttl_seconds(100);
|
|
metric2ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
|
|
auto metric2ActivationTrigger2 = metric2Activation->add_event_activation();
|
|
metric2ActivationTrigger2->set_atom_matcher_id(jobFinishMatcher.id());
|
|
metric2ActivationTrigger2->set_ttl_seconds(200);
|
|
metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
|
|
|
|
// Send the config.
|
|
StatsService service(nullptr, nullptr);
|
|
string serialized = config1.SerializeAsString();
|
|
service.addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
|
|
|
|
// Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
|
|
StatsdConfig tmpConfig;
|
|
ConfigKey cfgKey1(uid, configId);
|
|
EXPECT_TRUE(StorageManager::readConfigFromDisk(cfgKey1, &tmpConfig));
|
|
|
|
// Metric 1 is not active.
|
|
// Metric 2 is not active.
|
|
// Metric 3 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
sp<StatsLogProcessor> processor = service.mProcessor;
|
|
EXPECT_EQ(1, processor->mMetricsManagers.size());
|
|
auto it = processor->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor->mMetricsManagers.end());
|
|
auto& metricsManager1 = it->second;
|
|
EXPECT_TRUE(metricsManager1->isActive());
|
|
EXPECT_EQ(3, metricsManager1->mAllMetricProducers.size());
|
|
|
|
auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
|
|
EXPECT_EQ(metricId1, metricProducer1->getMetricId());
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
|
|
auto& metricProducer2 = metricsManager1->mAllMetricProducers[1];
|
|
EXPECT_EQ(metricId2, metricProducer2->getMetricId());
|
|
EXPECT_FALSE(metricProducer2->isActive());
|
|
|
|
auto& metricProducer3 = metricsManager1->mAllMetricProducers[2];
|
|
EXPECT_EQ(metricId3, metricProducer3->getMetricId());
|
|
EXPECT_TRUE(metricProducer3->isActive());
|
|
|
|
// Check event activations.
|
|
EXPECT_EQ(metricsManager1->mAllAtomMatchers.size(), 4);
|
|
EXPECT_EQ(metricsManager1->mAllAtomMatchers[0]->getId(),
|
|
metric1ActivationTrigger1->atom_matcher_id());
|
|
const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
|
|
|
|
EXPECT_EQ(metricsManager1->mAllAtomMatchers[1]->getId(),
|
|
metric1ActivationTrigger2->atom_matcher_id());
|
|
const auto& activation2 = metricProducer1->mEventActivationMap.at(1);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
|
|
EXPECT_EQ(0, activation2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
|
|
|
|
EXPECT_EQ(metricsManager1->mAllAtomMatchers[2]->getId(),
|
|
metric2ActivationTrigger1->atom_matcher_id());
|
|
const auto& activation3 = metricProducer2->mEventActivationMap.at(2);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns);
|
|
EXPECT_EQ(0, activation3->start_ns);
|
|
EXPECT_EQ(kNotActive, activation3->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType);
|
|
|
|
EXPECT_EQ(metricsManager1->mAllAtomMatchers[3]->getId(),
|
|
metric2ActivationTrigger2->atom_matcher_id());
|
|
const auto& activation4 = metricProducer2->mEventActivationMap.at(3);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns);
|
|
EXPECT_EQ(0, activation4->start_ns);
|
|
EXPECT_EQ(kNotActive, activation4->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation4->activationType);
|
|
// }}}------------------------------------------------------------------------------
|
|
|
|
// Trigger Activation 1 for Metric 1. Should activate on boot.
|
|
// Trigger Activation 4 for Metric 2. Should activate immediately.
|
|
long configAddedTimeNs = metricsManager1->mLastReportTimeNs;
|
|
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
|
|
auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 1 + configAddedTimeNs);
|
|
processor->OnLogEvent(event.get());
|
|
|
|
event = CreateFinishScheduledJobEvent(attributions1, "finish1", 2 + configAddedTimeNs);
|
|
processor->OnLogEvent(event.get());
|
|
|
|
// Metric 1 is not active; Activation 1 set to kActiveOnBoot
|
|
// Metric 2 is active. Activation 4 set to kActive
|
|
// Metric 3 is active.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_FALSE(metricProducer1->isActive());
|
|
EXPECT_EQ(0, activation1->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1->state);
|
|
EXPECT_EQ(0, activation2->start_ns);
|
|
EXPECT_EQ(kNotActive, activation2->state);
|
|
|
|
EXPECT_TRUE(metricProducer2->isActive());
|
|
EXPECT_EQ(0, activation3->start_ns);
|
|
EXPECT_EQ(kNotActive, activation3->state);
|
|
EXPECT_EQ(2 + configAddedTimeNs, activation4->start_ns);
|
|
EXPECT_EQ(kActive, activation4->state);
|
|
|
|
EXPECT_TRUE(metricProducer3->isActive());
|
|
// }}}-----------------------------------------------------------------------------
|
|
|
|
// Can't fake time with StatsService.
|
|
// Lets get a time close to the system server death time and make sure it's sane.
|
|
int64_t approximateSystemServerDeath = getElapsedRealtimeNs();
|
|
EXPECT_TRUE(approximateSystemServerDeath > 2 + configAddedTimeNs);
|
|
EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
|
|
|
|
// System server dies.
|
|
service.binderDied(nullptr);
|
|
|
|
// We should have a new metrics manager. Lets get it and ensure activation status is restored.
|
|
// {{{---------------------------------------------------------------------------
|
|
EXPECT_EQ(1, processor->mMetricsManagers.size());
|
|
it = processor->mMetricsManagers.find(cfgKey1);
|
|
EXPECT_TRUE(it != processor->mMetricsManagers.end());
|
|
auto& metricsManager2 = it->second;
|
|
EXPECT_TRUE(metricsManager2->isActive());
|
|
EXPECT_EQ(3, metricsManager2->mAllMetricProducers.size());
|
|
|
|
auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
|
|
EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
|
|
EXPECT_FALSE(metricProducer1001->isActive());
|
|
|
|
auto& metricProducer1002 = metricsManager2->mAllMetricProducers[1];
|
|
EXPECT_EQ(metricId2, metricProducer1002->getMetricId());
|
|
EXPECT_TRUE(metricProducer1002->isActive());
|
|
|
|
auto& metricProducer1003 = metricsManager2->mAllMetricProducers[2];
|
|
EXPECT_EQ(metricId3, metricProducer1003->getMetricId());
|
|
EXPECT_TRUE(metricProducer1003->isActive());
|
|
|
|
// Check event activations.
|
|
// Activation 1 is kActiveOnBoot.
|
|
// Activation 2 and 3 are not active.
|
|
// Activation 4 is active.
|
|
EXPECT_EQ(metricsManager2->mAllAtomMatchers.size(), 4);
|
|
EXPECT_EQ(metricsManager2->mAllAtomMatchers[0]->getId(),
|
|
metric1ActivationTrigger1->atom_matcher_id());
|
|
const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
|
|
EXPECT_EQ(0, activation1001->start_ns);
|
|
EXPECT_EQ(kActiveOnBoot, activation1001->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType);
|
|
|
|
EXPECT_EQ(metricsManager2->mAllAtomMatchers[1]->getId(),
|
|
metric1ActivationTrigger2->atom_matcher_id());
|
|
const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns);
|
|
EXPECT_EQ(0, activation1002->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1002->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType);
|
|
|
|
EXPECT_EQ(metricsManager2->mAllAtomMatchers[2]->getId(),
|
|
metric2ActivationTrigger1->atom_matcher_id());
|
|
const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2);
|
|
EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
|
|
EXPECT_EQ(0, activation1003->start_ns);
|
|
EXPECT_EQ(kNotActive, activation1003->state);
|
|
EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType);
|
|
|
|
EXPECT_EQ(metricsManager2->mAllAtomMatchers[3]->getId(),
|
|
metric2ActivationTrigger2->atom_matcher_id());
|
|
const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3);
|
|
EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns);
|
|
EXPECT_EQ(2 + configAddedTimeNs, activation1004->start_ns);
|
|
EXPECT_EQ(kActive, activation1004->state);
|
|
EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
|
|
// }}}------------------------------------------------------------------------------
|
|
|
|
// Clear the data stored on disk as a result of the system server death.
|
|
vector<uint8_t> buffer;
|
|
processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true,
|
|
ADB_DUMP, FAST, &buffer);
|
|
}
|
|
|
|
#else
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif
|
|
|
|
} // namespace statsd
|
|
} // namespace os
|
|
} // namespace android
|