Merge "DO NOT MERGE Don't lock listener delivery" into rvc-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index 66d6af9..00c8fdc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -111,6 +111,7 @@
method public void setLaunchActivityType(int);
method public void setLaunchTaskId(int);
method public void setLaunchWindowingMode(int);
+ method public void setTaskAlwaysOnTop(boolean);
method public void setTaskOverlay(boolean, boolean);
}
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 0868aaa..fab8e68 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -766,805 +766,726 @@
{(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
EXPECT_FALSE(valueProducer->mCondition);
}
+TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(20);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0]; ValueMetricProducer::BaseInfo
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(10,
-// curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(30, curInterval.value.long_value);
-//
-// valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-// assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-// valueProducer.mCondition = ConditionState::kFalse;
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has 1 slice
-// EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-//
-// valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(20);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(20, curInterval.value.long_value);
-//
-// shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 30);
-// event3->write(1);
-// event3->write(30);
-// event3->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(50, curInterval.value.long_value);
-//
-// valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
-// shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
-// event4->write(1);
-// event4->write(40);
-// event4->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(50, curInterval.value.long_value);
-//
-// valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-// assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
-//}
-//
-// TEST(ValueMetricProducerTest, TestAnomalyDetection) {
-// sp<AlarmMonitor> alarmMonitor;
-// Alert alert;
-// alert.set_id(101);
-// alert.set_metric_id(metricId);
-// alert.set_trigger_if_sum_gt(130);
-// alert.set_num_buckets(2);
-// const int32_t refPeriodSec = 3;
-// alert.set_refractory_period_secs(refPeriodSec);
-//
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
-// bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-// sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-//
-// shared_ptr<LogEvent> event1
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1 * NS_PER_SEC);
-// event1->write(161);
-// event1->write(10); // value of interest
-// event1->init();
-// shared_ptr<LogEvent> event2
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 + NS_PER_SEC);
-// event2->write(162);
-// event2->write(20); // value of interest
-// event2->init();
-// shared_ptr<LogEvent> event3
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC);
-// event3->write(163);
-// event3->write(130); // value of interest
-// event3->init();
-// shared_ptr<LogEvent> event4
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC);
-// event4->write(35);
-// event4->write(1); // value of interest
-// event4->init();
-// shared_ptr<LogEvent> event5
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
-// event5->write(45);
-// event5->write(150); // value of interest
-// event5->init();
-// shared_ptr<LogEvent> event6
-// = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10 *
-// NS_PER_SEC);
-// event6->write(25);
-// event6->write(160); // value of interest
-// event6->init();
-//
-// // Two events in bucket #0.
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-// // Value sum == 30 <= 130.
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // One event in bucket #2. No alarm as bucket #0 is trashed out.
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-// // Value sum == 130 <= 130.
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // Three events in bucket #3.
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-// // Anomaly at event 4 since Value sum == 131 > 130!
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
-// // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
-// // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//}
-//
-//// Test value metric no condition, the pull on bucket boundary come in time and too late
-// TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-// vector<shared_ptr<LogEvent>> allData;
-// // pull 1
-// allData.clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(tagId);
-// event->write(11);
-// event->init();
-// allData.push_back(event);
-//
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0];
-//
-// // startUpdated:true sum:0 start:11
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(11, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-// // pull 2 at correct time
-// allData.clear();
-// event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-// event->write(tagId);
-// event->write(23);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// // tartUpdated:false sum:12
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(23, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
-//
-// // pull 3 come late.
-// // The previous bucket gets closed with error. (Has start value 23, no ending)
-// // Another bucket gets closed with error. (No start, but ending with 36)
-// // The new bucket is back to normal.
-// allData.clear();
-// event = make_shared<LogEvent>(tagId, bucket6StartTimeNs + 1);
-// event->write(tagId);
-// event->write(36);
-// event->init();
-// allData.push_back(event);
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// // startUpdated:false sum:12
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(36, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
-//}
-//
-///*
-// * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
-// * was delivered late.
-// */
-// TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // condition becomes true
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// // condition becomes false
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(tagId);
-// event->write(120);
-// event->init();
-// data->push_back(event);
-// return true;
-// }));
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(100, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-// // pull on bucket boundary come late, condition change happens before it
-// valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-// EXPECT_EQ(false, curBaseInfo.hasBase);
-//
-// // Now the alarm is delivered.
-// // since the condition turned to off before this pull finish, it has no effect
-// vector<shared_ptr<LogEvent>> allData;
-// allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, curInterval.hasValue);
-//}
-//
-///*
-// * Test pulled event with non sliced condition. The pull on boundary come late, after the
-// condition
-// * change to false, and then true again. This is due to alarm delivered late.
-// */
-// TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-// EXPECT_CALL(*pullerManager, Pull(tagId, _))
-// // condition becomes true
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-// event->write(tagId);
-// event->write(100);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// // condition becomes false
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-// event->write(tagId);
-// event->write(120);
-// event->init();
-// data->push_back(event);
-// return true;
-// }))
-// // condition becomes true again
-// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-// data->clear();
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs +
-// 25); event->write(tagId); event->write(130); event->init();
-// data->push_back(event);
-// return true;
-// }));
-//
-// sp<ValueMetricProducer> valueProducer =
-// ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-// metric);
-//
-// valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo =
-// valueProducer->mCurrentBaseInfo.begin()->second[0];
-// // startUpdated:false sum:0 start:100
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(100, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-// // pull on bucket boundary come late, condition change happens before it
-// valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-// EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(false, curBaseInfo.hasBase);
-// EXPECT_EQ(false, curInterval.hasValue);
-//
-// // condition changed to true again, before the pull alarm is delivered
-// valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(130, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-//
-// // Now the alarm is delivered, but it is considered late, the data will be used
-// // for the new bucket since it was just pulled.
-// vector<shared_ptr<LogEvent>> allData;
-// allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 50, 140));
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
-//
-// curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(140, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-// EXPECT_EQ(10, curInterval.value.long_value);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//
-// allData.clear();
-// allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
-// valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-// assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
-// {bucketSizeNs - 8, bucketSizeNs - 24});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_aggregation_type(ValueMetric::MIN);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(20);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(10, curInterval.value.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(10, curInterval.value.long_value);
-//
-// valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-// assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_aggregation_type(ValueMetric::MAX);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(20);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(10, curInterval.value.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(20, curInterval.value.long_value);
-//
-// valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-// /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); */
-// /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); */
-// /* EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value); */
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_aggregation_type(ValueMetric::AVG);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(15);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval;
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(10, curInterval.value.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-// EXPECT_EQ(1, curInterval.sampleSize);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(25, curInterval.value.long_value);
-// EXPECT_EQ(2, curInterval.sampleSize);
-//
-// valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-//
-// EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value
-// -
-// 12.5) < epsilon);
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_aggregation_type(ValueMetric::SUM);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-// event2->write(1);
-// event2->write(15);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(10, curInterval.value.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(25, curInterval.value.long_value);
-//
-// valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-// assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.set_aggregation_type(ValueMetric::MIN);
-// metric.set_use_diff(true);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
-// event2->write(1);
-// event2->write(15);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(10, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// EXPECT_EQ(true, curInterval.hasValue);
-// EXPECT_EQ(5, curInterval.value.long_value);
-//
-// // no change in data.
-// shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-// event3->write(1);
-// event3->write(15);
-// event3->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(15, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
-// event4->write(1);
-// event4->write(15);
-// event4->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(15, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-// assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
-// ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-// metric.mutable_value_field()->add_child()->set_field(3);
-// metric.set_aggregation_type(ValueMetric::MIN);
-// metric.set_use_diff(true);
-//
-// UidMap uidMap;
-// SimpleAtomMatcher atomMatcher;
-// atomMatcher.set_atom_id(tagId);
-// sp<EventMatcherWizard> eventMatcherWizard =
-// new EventMatcherWizard({new SimpleLogMatchingTracker(
-// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-// ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-// eventMatcherWizard, -1, bucketStartTimeNs,
-// bucketStartTimeNs, pullerManager);
-//
-// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-// event1->write(1);
-// event1->write(10);
-// event1->write(20);
-// event1->init();
-// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
-// event2->write(1);
-// event2->write(15);
-// event2->write(22);
-// event2->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// ValueMetricProducer::Interval curInterval =
-// valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(10, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(20, curBaseInfo.base.long_value);
-// EXPECT_EQ(false, curInterval.hasValue);
-//
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-// // has one slice
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curInterval.hasValue);
-// EXPECT_EQ(5, curInterval.value.long_value);
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-// EXPECT_EQ(true, curInterval.hasValue);
-// EXPECT_EQ(2, curInterval.value.long_value);
-//
-// // no change in first value field
-// shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-// event3->write(1);
-// event3->write(15);
-// event3->write(25);
-// event3->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(15, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(25, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
-// event4->write(1);
-// event4->write(15);
-// event4->write(29);
-// event4->init();
-// valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-// EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(15, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-// curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-// curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-// EXPECT_EQ(true, curBaseInfo.hasBase);
-// EXPECT_EQ(29, curBaseInfo.base.long_value);
-// EXPECT_EQ(true, curInterval.hasValue);
-//
-// valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-//
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-// EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-// EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
-// EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
-//
-// EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
-// EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
-// EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
-// EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
-// EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
-//
-// EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
-// EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
-// EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
-//}
-//
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(30, curInterval.value.long_value);
+
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+ valueProducer.mCondition = ConditionState::kFalse;
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has 1 slice
+ EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+
+ valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(20, curInterval.value.long_value);
+
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 1, 30);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(50, curInterval.value.long_value);
+
+ valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 1, 40);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(50, curInterval.value.long_value);
+
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
+}
+
+TEST(ValueMetricProducerTest, TestAnomalyDetection) {
+ sp<AlarmMonitor> alarmMonitor;
+ Alert alert;
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
+ alert.set_trigger_if_sum_gt(130);
+ alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 3;
+ alert.set_refractory_period_secs(refPeriodSec);
+
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 1 * NS_PER_SEC, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 2 + NS_PER_SEC, 20);
+
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event3, tagId,
+ bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, 130);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event4, tagId,
+ bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC, 1);
+
+ LogEvent event5(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event5, tagId,
+ bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, 150);
+
+ LogEvent event6(/*uid=*/0, /*pid=*/0);
+ CreateRepeatedValueLogEvent(&event6, tagId,
+ bucketStartTimeNs + 3 * bucketSizeNs + 10 * NS_PER_SEC, 160);
+
+ // Two events in bucket #0.
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ // Value sum == 30 <= 130.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // One event in bucket #2. No alarm as bucket #0 is trashed out.
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ // Value sum == 130 <= 130.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // Three events in bucket #3.
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ // Anomaly at event 4 since Value sum == 131 > 130!
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
+ // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
+ // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event6.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+}
+
+// Test value metric no condition, the pull on bucket boundary come in time and too late
+TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ vector<shared_ptr<LogEvent>> allData;
+ // pull 1
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
+
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+
+ // startUpdated:true sum:0 start:11
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+ // pull 2 at correct time
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ // tartUpdated:false sum:12
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(23, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
+
+ // pull 3 come late.
+ // The previous bucket gets closed with error. (Has start value 23, no ending)
+ // Another bucket gets closed with error. (No start, but ending with 36)
+ // The new bucket is back to normal.
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ // startUpdated:false sum:12
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
+}
+
+/*
+ * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
+ * was delivered late.
+ */
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // condition becomes true
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+ return true;
+ }))
+ // condition becomes false
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
+ return true;
+ }));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+ // pull on bucket boundary come late, condition change happens before it
+ valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+
+ // Now the alarm is delivered.
+ // since the condition turned to off before this pull finish, it has no effect
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+}
+
+/*
+* Test pulled event with non sliced condition. The pull on boundary come late, after the
+condition
+* change to false, and then true again. This is due to alarm delivered late.
+*/
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // condition becomes true
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+ return true;
+ }))
+ // condition becomes false
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
+ return true;
+ }))
+ // condition becomes true again
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130));
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ // startUpdated:false sum:0 start:100
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+ // pull on bucket boundary come late, condition change happens before it
+ valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ // condition changed to true again, before the pull alarm is delivered
+ valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(130, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ // Now the alarm is delivered, but it is considered late, the data will be used
+ // for the new bucket since it was just pulled.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
+
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(10, curInterval.value.long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 160));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
+ {bucketSizeNs - 8, bucketSizeNs - 24});
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_aggregation_type(ValueMetric::MIN);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_aggregation_type(ValueMetric::MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(20, curInterval.value.long_value);
+
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+ /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); */
+ /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); */
+ /* EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value); */
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_aggregation_type(ValueMetric::AVG);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval;
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(1, curInterval.sampleSize);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(25, curInterval.value.long_value);
+ EXPECT_EQ(2, curInterval.sampleSize);
+
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+
+ EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
+ 12.5) < epsilon);
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_aggregation_type(ValueMetric::SUM);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(10, curInterval.value.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(25, curInterval.value.long_value);
+
+ valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_aggregation_type(ValueMetric::MIN);
+ metric.set_use_diff(true);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(5, curInterval.value.long_value);
+
+ // no change in data.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateTwoValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15);
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.mutable_value_field()->add_child()->set_field(3);
+ metric.set_aggregation_type(ValueMetric::MIN);
+ metric.set_use_diff(true);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10, 20);
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15, 22);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(20, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(5, curInterval.value.long_value);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(2, curInterval.value.long_value);
+
+ // no change in first value field
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15, 25);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(25, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ CreateThreeValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15, 29);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(29, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+
+ EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
+ EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
+ EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
+ EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
+
+ EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
+ EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
+}
+
///*
// * Tests zero default base.
// */
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4aacf48..7fd02112 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -209,6 +209,12 @@
"android.activity.pendingIntentLaunchFlags";
/**
+ * See {@link #setTaskAlwaysOnTop}.
+ * @hide
+ */
+ private static final String KEY_TASK_ALWAYS_ON_TOP = "android.activity.alwaysOnTop";
+
+ /**
* See {@link #setTaskOverlay}.
* @hide
*/
@@ -337,6 +343,7 @@
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
+ private boolean mTaskAlwaysOnTop;
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
private boolean mAvoidMoveToFront;
@@ -971,6 +978,7 @@
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
mPendingIntentLaunchFlags = opts.getInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, 0);
+ mTaskAlwaysOnTop = opts.getBoolean(KEY_TASK_ALWAYS_ON_TOP, false);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@@ -1300,6 +1308,22 @@
}
/**
+ * Set's whether the task for the activity launched with this option should always be on top.
+ * @hide
+ */
+ @TestApi
+ public void setTaskAlwaysOnTop(boolean alwaysOnTop) {
+ mTaskAlwaysOnTop = alwaysOnTop;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getTaskAlwaysOnTop() {
+ return mTaskAlwaysOnTop;
+ }
+
+ /**
* Set's whether the activity launched with this option should be a task overlay. That is the
* activity will always be the top activity of the task.
* @param canResume {@code false} if the task will also not be moved to the front of the stack.
@@ -1556,6 +1580,9 @@
if (mPendingIntentLaunchFlags != 0) {
b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
}
+ if (mTaskAlwaysOnTop) {
+ b.putBoolean(KEY_TASK_ALWAYS_ON_TOP, mTaskAlwaysOnTop);
+ }
if (mTaskOverlay) {
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
}
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
index 9d6c3d6..a448e13 100644
--- a/core/java/android/app/ITaskOrganizerController.aidl
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -32,6 +32,11 @@
void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
/**
+ * Unregisters a previously registered task organizer.
+ */
+ void unregisterTaskOrganizer(ITaskOrganizer organizer);
+
+ /**
* Apply multiple WindowContainer operations at once.
* @param organizer If non-null this transaction will use the synchronization
* scheme described in BLASTSyncEngine.java. The SurfaceControl transaction
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c7a1391..14ca7cb 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -27,8 +27,10 @@
import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WaitResult.LAUNCH_STATE_COLD;
import static android.app.WaitResult.LAUNCH_STATE_HOT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -167,6 +169,8 @@
// The display to launch the activity onto, barring any strong reason to do otherwise.
private int mPreferredDisplayId;
+ // The windowing mode to apply to the root task, if possible
+ private int mPreferredWindowingMode;
private Task mInTask;
@VisibleForTesting
@@ -538,6 +542,7 @@
mStartFlags = starter.mStartFlags;
mSourceRecord = starter.mSourceRecord;
mPreferredDisplayId = starter.mPreferredDisplayId;
+ mPreferredWindowingMode = starter.mPreferredWindowingMode;
mInTask = starter.mInTask;
mAddingToTask = starter.mAddingToTask;
@@ -1493,8 +1498,6 @@
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
- final int preferredWindowingMode = mLaunchParams.mWindowingMode;
-
computeLaunchingTaskFlags();
computeSourceStack();
@@ -1564,6 +1567,14 @@
if (!mAvoidMoveToFront && mDoResume) {
mTargetStack.moveToFront("reuseOrNewTask");
+ if (mOptions != null) {
+ if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED) {
+ mTargetStack.setWindowingMode(mPreferredWindowingMode);
+ }
+ if (mOptions.getTaskAlwaysOnTop()) {
+ mTargetStack.setAlwaysOnTop(true);
+ }
+ }
}
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
@@ -1627,7 +1638,7 @@
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
- preferredWindowingMode, mPreferredDisplayId, mTargetStack);
+ mPreferredWindowingMode, mPreferredDisplayId, mTargetStack);
return START_SUCCESS;
}
@@ -1680,9 +1691,10 @@
mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
- mPreferredDisplayId =
- mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
- : DEFAULT_DISPLAY;
+ mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
+ ? mLaunchParams.mPreferredDisplayId
+ : DEFAULT_DISPLAY;
+ mPreferredWindowingMode = mLaunchParams.mWindowingMode;
}
private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
@@ -2006,6 +2018,7 @@
mStartFlags = 0;
mSourceRecord = null;
mPreferredDisplayId = INVALID_DISPLAY;
+ mPreferredWindowingMode = WINDOWING_MODE_UNDEFINED;
mInTask = null;
mAddingToTask = false;
@@ -2054,9 +2067,10 @@
// after we located a reusable task (which might be resided in another display).
mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
- mPreferredDisplayId =
- mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
- : DEFAULT_DISPLAY;
+ mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
+ ? mLaunchParams.mPreferredDisplayId
+ : DEFAULT_DISPLAY;
+ mPreferredWindowingMode = mLaunchParams.mWindowingMode;
mLaunchMode = r.launchMode;
@@ -2098,7 +2112,7 @@
}
if (mOptions != null) {
- if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
+ if (mOptions.getLaunchTaskId() != INVALID_TASK_ID && mOptions.getTaskOverlay()) {
r.setTaskOverlay(true);
if (!mOptions.canTaskOverlayResume()) {
final Task task = mRootWindowContainer.anyTaskForId(
@@ -2291,6 +2305,15 @@
* if not or an ActivityRecord with the task into which the new activity should be added.
*/
private Task getReusableTask() {
+ // If a target task is specified, try to reuse that one
+ if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
+ Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
+ if (launchTask != null) {
+ return launchTask;
+ }
+ return null;
+ }
+
// We may want to try to place the new activity in to an existing task. We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
@@ -2304,12 +2327,7 @@
// same component, then instead of launching bring that one to the front.
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
- if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
- Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
- if (launchTask != null) {
- return launchTask;
- }
- } else if (putIntoExistingTask) {
+ if (putIntoExistingTask) {
if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ee36db9..a4bdfb3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
@@ -87,7 +88,8 @@
final InsetsSourceProvider provider = target.getControllableInsetProvider();
final @InternalInsetsType int type = provider != null
? provider.getSource().getType() : ITYPE_INVALID;
- return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode());
+ return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
+ target.isAlwaysOnTop());
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -95,7 +97,9 @@
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
final @WindowingMode int windowingMode = token != null
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
- return getInsetsForTypeAndWindowingMode(type, windowingMode);
+ final boolean alwaysOnTop = token != null
+ ? token.isAlwaysOnTop() : false;
+ return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
}
private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
@@ -113,7 +117,7 @@
/** @see #getInsetsForDispatch */
private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
- @WindowingMode int windowingMode) {
+ @WindowingMode int windowingMode, boolean isAlwaysOnTop) {
InsetsState state = mState;
if (type != ITYPE_INVALID) {
@@ -147,7 +151,8 @@
}
}
- if (WindowConfiguration.isFloating(windowingMode)) {
+ if (WindowConfiguration.isFloating(windowingMode)
+ || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
state = new InsetsState(state);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_NAVIGATION_BAR);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8f09f3f..cc52cb4 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -231,7 +231,8 @@
}
}
- void unregisterTaskOrganizer(ITaskOrganizer organizer) {
+ @Override
+ public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
state.unlinkDeath();
if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index c449049..2acb647 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -51,6 +51,7 @@
opts.setLaunchTaskId(Integer.MAX_VALUE);
opts.setLockTaskEnabled(true);
opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
+ opts.setTaskAlwaysOnTop(true);
opts.setTaskOverlay(true, true);
opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
Bundle optsBundle = opts.toBundle();
@@ -67,6 +68,7 @@
assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId());
assertTrue(restoredOpts.getLockTaskMode());
assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint());
+ assertTrue(restoredOpts.getTaskAlwaysOnTop());
assertTrue(restoredOpts.getTaskOverlay());
assertTrue(restoredOpts.canTaskOverlayResume());
assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index a380ece..bfb126f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -131,6 +132,21 @@
}
@Test
+ public void testStripForDispatch_multiwindow_alwaysOnTop() {
+ final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ app.setAlwaysOnTop(true);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+ }
+
+ @Test
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index efea91a..9fe1883 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -48,9 +48,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
+import androidx.core.os.BuildCompat;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
@@ -64,6 +66,13 @@
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ private boolean isAtLeastR() {
+ // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
+ // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
+ // releasing Android R.
+ return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
+ }
+
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -269,25 +278,36 @@
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.setOwnerUid(123);
+ if (isAtLeastR()) {
+ netCap.setOwnerUid(123);
+ }
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 15);
+ testParcelSane(netCap);
}
@Test
public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
final NetworkCapabilities netCap = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
- .setRequestorUid(9304)
- .setRequestorPackageName("com.android.test")
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
+ if (isAtLeastR()) {
+ netCap.setRequestorPackageName("com.android.test");
+ netCap.setRequestorUid(9304);
+ }
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 15);
+ testParcelSane(netCap);
}
+ private void testParcelSane(NetworkCapabilities cap) {
+ if (isAtLeastR()) {
+ assertParcelSane(cap, 15);
+ } else {
+ assertParcelSane(cap, 11);
+ }
+ }
@Test
public void testOemPaid() {