Merge "metric activation on boot"
This commit is contained in:
committed by
Android (Google) Code Review
commit
aa92c88243
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user