Merge "metric activation on boot"

This commit is contained in:
TreeHugger Robot
2019-02-09 01:07:49 +00:00
committed by Android (Google) Code Review
8 changed files with 191 additions and 13 deletions

View File

@@ -526,9 +526,10 @@ void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId());
proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid());
vector<const MetricProducer*> acrtiveMetrics;
pair.second->getActiveMetrics(acrtiveMetrics);
for (const MetricProducer* metric : acrtiveMetrics) {
vector<MetricProducer*> activeMetrics;
pair.second->prepForShutDown(currentTimeNs);
pair.second->getActiveMetrics(activeMetrics);
for (MetricProducer* metric : activeMetrics) {
if (metric->isActive()) {
uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
FIELD_ID_ACTIVE_METRIC);

View File

@@ -195,6 +195,7 @@ private:
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);

View File

@@ -107,6 +107,10 @@ void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedT
if (it == mEventActivationMap.end()) {
return;
}
if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT) {
it->second.state = ActivationState::kActiveOnBoot;
return;
}
it->second.activation_ns = elapsedTimestampNs;
it->second.state = ActivationState::kActive;
mIsActive = true;
@@ -116,12 +120,19 @@ void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtl
if (mEventActivationMap.size() == 0) {
return;
}
auto& activation = mEventActivationMap.begin()->second;
activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns;
activation.state = kActive;
mIsActive = true;
VLOG("setting new activation time to %lld, %lld, %lld", (long long)activation.activation_ns,
(long long)currentTimeNs, (long long)remainingTtlNs);
for (auto& pair : mEventActivationMap) {
auto& activation = pair.second;
if (activation.ttl_ns >= remainingTtlNs) {
activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns;
activation.state = kActive;
mIsActive = true;
VLOG("setting new activation time to %lld, %lld, %lld",
(long long)activation.activation_ns, (long long)currentTimeNs,
(long long)remainingTtlNs);
return;
}
}
ALOGE("Required ttl is longer than all possible activations.");
}
int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
@@ -135,6 +146,19 @@ int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
return maxTtl;
}
void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) {
if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) {
return;
}
for (auto& activation : mEventActivationMap) {
if (activation.second.state == kActiveOnBoot) {
activation.second.state = kActive;
activation.second.activation_ns = currentTimeNs;
mIsActive = true;
}
}
}
} // namespace statsd
} // namespace os
} // namespace android

View File

@@ -37,12 +37,13 @@ namespace statsd {
// If the metric has no activation requirement, it will be active once the metric producer is
// created.
// If the metric needs to be activated by atoms, the metric producer will start
// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
// when it reaches the duration limit (timebomb). If the activation event arrives again before
// or after it expires, the event producer will be re-activated and ttl will be reset.
// with kNotActive state, turn to kActive or kActiveOnBoot when the activation event arrives, become
// kNotActive when it reaches the duration limit (timebomb). If the activation event arrives again
// before or after it expires, the event producer will be re-activated and ttl will be reset.
enum ActivationState {
kNotActive = 0,
kActive = 1,
kActiveOnBoot = 2,
};
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
@@ -218,8 +219,17 @@ public:
return isActiveLocked();
}
void prepActiveForBootIfNecessary(int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
prepActiveForBootIfNecessaryLocked(currentTimeNs);
}
void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
inline void setActivationType(const MetricActivation::ActivationType& activationType) {
mActivationType = activationType;
}
void flushIfExpire(int64_t elapsedTimestampNs);
protected:
@@ -243,6 +253,8 @@ protected:
return mIsActive;
}
void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs);
int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const;
void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
@@ -367,9 +379,12 @@ protected:
bool mIsActive;
MetricActivation::ActivationType mActivationType;
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
};
} // namespace statsd

View File

@@ -132,7 +132,7 @@ public:
return mIsActive;
}
inline void getActiveMetrics(std::vector<const MetricProducer*>& metrics) const {
inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const {
for (const auto& metric : mAllMetricProducers) {
if (metric->isActive()) {
metrics.push_back(metric.get());
@@ -140,6 +140,12 @@ public:
}
}
inline void prepForShutDown(int64_t currentTimeNs) {
for (const auto& metric : mAllMetricProducers) {
metric->prepActiveForBootIfNecessary(currentTimeNs);
}
}
void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
private:
@@ -271,6 +277,7 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
};
} // namespace statsd

View File

@@ -725,6 +725,8 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
ALOGE("Invalid metric tracker index.");
return false;
}
allMetricProducers[metricTrackerIndex]->setActivationType(
metric_activation.activation_type());
metricsWithActivation.push_back(metricTrackerIndex);
for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
const EventActivation& activation = metric_activation.event_activation(j);

View File

@@ -379,6 +379,13 @@ message EventActivation {
message MetricActivation {
optional int64 metric_id = 1;
enum ActivationType {
UNKNOWN = 0;
ACTIVATE_IMMEDIATELY = 1;
ACTIVATE_ON_BOOT = 2;
}
optional ActivationType activation_type = 3;
repeated EventActivation event_activation = 2;
}

View File

@@ -574,6 +574,127 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns);
}
TEST(StatsLogProcessorTest, TestActivationOnBoot) {
int uid = 1111;
// Setup a simple config, no activation
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(MetricActivation::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.activation_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.activation_ns);
EXPECT_EQ(kActiveOnBoot, activation1.state);
int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
processor->WriteMetricsActivationToDisk(shutDownTime);
EXPECT_TRUE(metricProducer1->isActive());
int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime);
EXPECT_EQ(100 * NS_PER_SEC, ttl1);
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.activation_ns);
EXPECT_EQ(kNotActive, activation1001.state);
processor2->LoadMetricsActivationFromDisk();
EXPECT_TRUE(metricProducer1001->isActive());
EXPECT_EQ(timeBase2 + ttl1 - activation1001.ttl_ns, activation1001.activation_ns);
}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif