|
|
|
|
@@ -12,14 +12,19 @@
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#include <android/binder_ibinder.h>
|
|
|
|
|
#include <android/binder_interface_utils.h>
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include "src/anomaly/DurationAnomalyTracker.h"
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "src/StatsLogProcessor.h"
|
|
|
|
|
#include "src/StatsService.h"
|
|
|
|
|
#include "src/anomaly/DurationAnomalyTracker.h"
|
|
|
|
|
#include "src/stats_log_util.h"
|
|
|
|
|
#include "tests/statsd_test_util.h"
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
using ::ndk::SharedRefBase;
|
|
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
|
namespace os {
|
|
|
|
|
@@ -29,6 +34,9 @@ namespace statsd {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
const int kConfigKey = 789130124;
|
|
|
|
|
const int kCallingUid = 0;
|
|
|
|
|
|
|
|
|
|
StatsdConfig CreateStatsdConfig(int num_buckets,
|
|
|
|
|
uint64_t threshold_ns,
|
|
|
|
|
DurationMetric::AggregationType aggregationType,
|
|
|
|
|
@@ -89,6 +97,13 @@ MetricDimensionKey dimensionKey2(
|
|
|
|
|
(int32_t)0x02010101), Value((int32_t)222))}),
|
|
|
|
|
DEFAULT_DIMENSION_KEY);
|
|
|
|
|
|
|
|
|
|
void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
|
|
|
|
|
string str;
|
|
|
|
|
config.SerializeToString(&str);
|
|
|
|
|
std::vector<uint8_t> configAsVec(str.begin(), str.end());
|
|
|
|
|
service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
@@ -98,16 +113,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
const uint64_t alert_id = config.alert(0).id();
|
|
|
|
|
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
|
|
|
|
|
|
|
|
|
|
int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
|
|
|
|
|
int64_t bucketSizeNs =
|
|
|
|
|
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
|
|
|
|
|
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
|
|
|
|
|
sendConfig(service, config);
|
|
|
|
|
|
|
|
|
|
ConfigKey cfgKey;
|
|
|
|
|
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
|
|
|
|
auto processor = service->mProcessor;
|
|
|
|
|
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
|
|
|
|
|
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
|
|
|
|
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
|
|
|
|
|
|
|
|
|
|
int64_t bucketStartTimeNs = processor->mTimeBaseNs;
|
|
|
|
|
int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
|
|
|
|
|
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
|
|
|
|
|
|
|
|
|
|
sp<AnomalyTracker> anomalyTracker =
|
|
|
|
|
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
|
|
|
|
|
|
|
|
|
|
@@ -158,12 +175,13 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
|
|
|
|
|
(uint32_t)alarmFiredTimestampSec0);
|
|
|
|
|
EXPECT_EQ(alarmFiredTimestampSec0,
|
|
|
|
|
processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec());
|
|
|
|
|
|
|
|
|
|
// Anomaly alarm fired.
|
|
|
|
|
auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
|
|
|
|
|
static_cast<uint32_t>(alarmFiredTimestampSec0));
|
|
|
|
|
ASSERT_EQ(1u, alarmSet.size());
|
|
|
|
|
processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
|
|
|
|
|
auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC);
|
|
|
|
|
processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
@@ -179,39 +197,39 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock wl1.
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(
|
|
|
|
|
roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2,
|
|
|
|
|
attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
|
|
|
|
|
(uint64_t)alarmFiredTimestampSec1);
|
|
|
|
|
|
|
|
|
|
// Release wakelock wl1.
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
|
|
|
|
|
attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec +
|
|
|
|
|
(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
|
|
|
|
|
auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
|
|
|
|
|
static_cast<uint32_t>(alarmFiredTimestampSec1));
|
|
|
|
|
ASSERT_EQ(0u, alarmSet.size());
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock wl1 near the end of bucket #0.
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Release the event at early bucket #1.
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
// Anomaly detected when stopping the alarm. The refractory period does not change.
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
|
|
|
|
|
@@ -236,17 +254,17 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
|
|
|
|
|
// Condition turns true.
|
|
|
|
|
screen_off_event =
|
|
|
|
|
CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
|
|
|
|
|
CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
|
|
|
|
|
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
|
|
|
|
|
processor->OnLogEvent(screen_off_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Condition turns to false.
|
|
|
|
|
screen_on_event =
|
|
|
|
|
CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
|
|
|
|
|
android::view::DisplayStateEnum::DISPLAY_STATE_ON);
|
|
|
|
|
processor->OnLogEvent(screen_on_event.get());
|
|
|
|
|
int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1;
|
|
|
|
|
screen_on_event = CreateScreenStateChangedEvent(
|
|
|
|
|
condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
|
|
|
|
|
processor->OnLogEvent(screen_on_event.get(), condition_false_time);
|
|
|
|
|
// Condition turns to false. Cancelled the alarm.
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
// Detected one anomaly.
|
|
|
|
|
@@ -262,12 +280,11 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
|
|
|
|
|
attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
EXPECT_EQ(refractory_period_sec +
|
|
|
|
|
(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
}
|
|
|
|
|
@@ -279,16 +296,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
|
|
|
|
|
const uint64_t alert_id = config.alert(0).id();
|
|
|
|
|
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
|
|
|
|
|
|
|
|
|
|
int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
|
|
|
|
|
int64_t bucketSizeNs =
|
|
|
|
|
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
|
|
|
|
|
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
|
|
|
|
|
sendConfig(service, config);
|
|
|
|
|
|
|
|
|
|
ConfigKey cfgKey;
|
|
|
|
|
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
|
|
|
|
auto processor = service->mProcessor;
|
|
|
|
|
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
|
|
|
|
|
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
|
|
|
|
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
|
|
|
|
|
|
|
|
|
|
int64_t bucketStartTimeNs = processor->mTimeBaseNs;
|
|
|
|
|
int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
|
|
|
|
|
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
|
|
|
|
|
|
|
|
|
|
sp<AnomalyTracker> anomalyTracker =
|
|
|
|
|
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
|
|
|
|
|
|
|
|
|
|
@@ -298,96 +317,97 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock "wc1" in bucket #0.
|
|
|
|
|
auto acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
|
|
|
|
|
CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Release wakelock "wc1" in bucket #0.
|
|
|
|
|
auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1;
|
|
|
|
|
auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock "wc1" in bucket #1.
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
|
|
|
|
|
attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock "wc2" in bucket #2.
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
|
|
|
|
|
|
|
|
|
|
// Release wakelock "wc2" in bucket #2.
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
|
|
|
|
|
attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec +
|
|
|
|
|
(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock "wc1" in bucket #2.
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
|
|
|
|
|
CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Release wakelock "wc1" in bucket #2.
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
|
|
|
|
|
attributionUids2, attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
|
|
|
|
|
attributionTags2, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec +
|
|
|
|
|
(int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
|
|
|
|
|
NS_PER_SEC +
|
|
|
|
|
1,
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
|
|
|
|
|
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
|
|
|
|
|
attributionUids3, attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
|
|
|
|
|
attributionTags3, "wl2");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time + 4);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
|
|
|
|
|
// The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
|
|
|
|
|
EXPECT_EQ(refractory_period_sec +
|
|
|
|
|
(int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) /
|
|
|
|
|
NS_PER_SEC +
|
|
|
|
|
1,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
}
|
|
|
|
|
@@ -396,20 +416,22 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
|
|
|
|
|
const int num_buckets = 2;
|
|
|
|
|
const uint64_t threshold_ns = 3 * NS_PER_SEC;
|
|
|
|
|
auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
|
|
|
|
|
int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
|
|
|
|
|
int64_t bucketSizeNs =
|
|
|
|
|
TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
|
|
|
|
|
|
|
|
|
|
const uint64_t alert_id = config.alert(0).id();
|
|
|
|
|
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
|
|
|
|
|
const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
|
|
|
|
|
config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
|
|
|
|
|
|
|
|
|
|
ConfigKey cfgKey;
|
|
|
|
|
auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
|
|
|
|
|
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
|
|
|
|
|
sendConfig(service, config);
|
|
|
|
|
|
|
|
|
|
auto processor = service->mProcessor;
|
|
|
|
|
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
|
|
|
|
|
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
|
|
|
|
|
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
|
|
|
|
|
|
|
|
|
|
int64_t bucketStartTimeNs = processor->mTimeBaseNs;
|
|
|
|
|
int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
|
|
|
|
|
|
|
|
|
|
sp<AnomalyTracker> anomalyTracker =
|
|
|
|
|
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
|
|
|
|
|
|
|
|
|
|
@@ -418,81 +440,81 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
|
|
|
|
|
processor->OnLogEvent(screen_off_event.get());
|
|
|
|
|
|
|
|
|
|
// Acquire wakelock "wc1" in bucket #0.
|
|
|
|
|
auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
|
|
|
|
|
auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Acquire the wakelock "wc1" again.
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
|
|
|
|
|
CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
// The alarm does not change.
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// Anomaly alarm fired late.
|
|
|
|
|
const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
|
|
|
|
|
auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
|
|
|
|
|
static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
|
|
|
|
|
ASSERT_EQ(1u, alarmSet.size());
|
|
|
|
|
processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
|
|
|
|
|
const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
|
|
|
|
|
auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs);
|
|
|
|
|
processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1;
|
|
|
|
|
auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
// Within the refractory period. No anomaly.
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
// A new wakelock, but still within refractory period.
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(
|
|
|
|
|
roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
// Still in the refractory period. No anomaly.
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
|
|
|
|
|
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(
|
|
|
|
|
roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
release_event =
|
|
|
|
|
CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get());
|
|
|
|
|
release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4;
|
|
|
|
|
release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(release_event.get(), release_event_time);
|
|
|
|
|
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
|
|
|
|
|
acquire_event =
|
|
|
|
|
CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
|
|
|
|
|
attributionUids1, attributionTags1, "wl1");
|
|
|
|
|
acquire_event = CreateAcquireWakelockEvent(
|
|
|
|
|
roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1,
|
|
|
|
|
attributionTags1, "wl1");
|
|
|
|
|
processor->OnLogEvent(acquire_event.get());
|
|
|
|
|
EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
|
|
|
|
|
EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
|
|
|
|
|
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|