Merge "Import translations. DO NOT MERGE" into qt-dev
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f4db0af..6178a4b 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -235,9 +235,12 @@
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
+ FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 68a8816..2bd4299 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -281,6 +281,8 @@
IntelligenceEventReported intelligence_event_reported =
188 [(log_from_module) = "intelligence"];
ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
+ RoleRequestResultReported role_request_result_reported =
+ 190 [(log_from_module) = "permissioncontroller"];
}
// Pulled events will start at field 10000.
@@ -3519,6 +3521,62 @@
message TombStoneOccurred {
}
+/*
+ * Information about a role request
+ *
+ * Logged from:
+ * packages/apps/PermissionController/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java
+ */
+message RoleRequestResultReported {
+ // UID of application requesting the role
+ optional int32 requesting_uid = 1;
+
+ // Package name of application requesting the role
+ optional string requesting_package_name = 2;
+
+ // The role to be granted
+ optional string role_name = 3;
+
+ // The count of applications qualifying for the role
+ optional int32 qualifying_count = 4;
+
+ // UID of application current granted the role
+ optional int32 current_uid = 5;
+
+ // Package name of application current granted the role
+ optional string current_package_name = 6;
+
+ // UID of another application that user chose to grant the role to, instead of the requesting
+ // application
+ optional int32 granted_another_uid = 7;
+
+ // Package name of another application that user chose to grant the role to, instead of the
+ // requesting application
+ optional string granted_another_package_name = 8;
+
+ enum Result {
+ UNDEFINED = 0;
+ // role request was ignored
+ IGNORED = 1;
+ // role request was ignored because it's already granted
+ IGNORED_ALREADY_GRANTED = 2;
+ // role request was ignored because the application isn't qualified
+ IGNORED_NOT_QUALIFIED = 3;
+ // role request was ignored because user said it should be always denied
+ IGNORED_USER_ALWAYS_DENIED = 4;
+ // role was granted by user action
+ USER_GRANTED = 5;
+ // role was denied by user action
+ USER_DENIED = 6;
+ // role was denied by user granting another application the role
+ USER_DENIED_GRANTED_ANOTHER = 7;
+ // role was denied and set to be always denied by the user
+ USER_DENIED_WITH_ALWAYS = 8;
+ }
+ // The result of the role request
+ optional Result result = 9;
+}
+
//////////////////////////////////////////////////////////////////////
// Pulled atoms below this line //
//////////////////////////////////////////////////////////////////////
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 45f6b35..4ea1386 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -120,8 +120,11 @@
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
+ FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 2f9afa5..49fe7ef 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -141,9 +141,6 @@
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
- if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
- pullAndMatchEventsLocked(startTimeNs);
- }
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
(long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
@@ -315,6 +312,12 @@
}
}
+void GaugeMetricProducer::prepareFistBucketLocked() {
+ if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
+ }
+}
+
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
switch(mSamplingType) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 9b99fb1..d3007c8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -122,6 +122,8 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
+ void prepareFistBucketLocked() override;
+
void pullAndMatchEventsLocked(const int64_t timestampNs);
const int mWhatMatcherIndex;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 5ed95ed..e22b853 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -25,6 +25,9 @@
using std::map;
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
+ if (!mIsActive) {
+ return;
+ }
int64_t eventTimeNs = event.GetElapsedTimestampNs();
// this is old event, maybe statsd restarted?
if (eventTimeNs < mTimeBaseNs) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 70fbd47..750566d 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -250,6 +250,11 @@
mActivationType = activationType;
}
+ void prepareFistBucket() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ prepareFistBucketLocked();
+ }
+
void flushIfExpire(int64_t elapsedTimestampNs);
protected:
@@ -281,6 +286,7 @@
void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
+ virtual void prepareFistBucketLocked() {};
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 00ae3b7..d05bb8b 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -266,9 +266,12 @@
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
+ FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
+ FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondition);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index c44ea8a..0bd6e62 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -144,6 +144,9 @@
mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) ||
HasPositionALL(metric.dimensions_in_condition());
+ int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
+ mCurrentBucketNum += numBucketsForward;
+
flushIfNeededLocked(startTimeNs);
if (mIsPulled) {
@@ -156,10 +159,6 @@
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
- // Kicks off the puller immediately if condition is true and diff based.
- if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(startTimeNs, mCondition);
- }
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
@@ -171,6 +170,13 @@
}
}
+void ValueMetricProducer::prepareFistBucketLocked() {
+ // Kicks off the puller immediately if condition is true and diff based.
+ if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+ }
+}
+
void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 8c19995..1821dea 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -113,6 +113,8 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
+ void prepareFistBucketLocked() override;
+
void dropDataLocked(const int64_t dropTimeNs) override;
// Calculate previous bucket end time based on current time.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 082382c..31b424e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -760,6 +760,12 @@
return true;
}
+void prepareFistBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
+ for (const auto& metric: allMetricProducers) {
+ metric->prepareFistBucket();
+ }
+}
+
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -817,6 +823,8 @@
return false;
}
+ prepareFistBucket(allMetricProducers);
+
return true;
}
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 946eccf..f01ad06 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -28,7 +28,10 @@
namespace {
-StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type) {
+const int64_t metricId = 123456;
+
+StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type,
+ bool useCondition = true) {
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
@@ -40,9 +43,11 @@
*config.add_predicate() = screenIsOffPredicate;
auto gaugeMetric = config.add_gauge_metric();
- gaugeMetric->set_id(123456);
+ gaugeMetric->set_id(metricId);
gaugeMetric->set_what(atomMatcher.id());
- gaugeMetric->set_condition(screenIsOffPredicate.id());
+ if (useCondition) {
+ gaugeMetric->set_condition(screenIsOffPredicate.id());
+ }
gaugeMetric->set_sampling_type(sampling_type);
gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
*gaugeMetric->mutable_dimensions_in_what() =
@@ -158,7 +163,7 @@
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
data.bucket_info(1).elapsed_timestamp_nanos(0));
- EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
@@ -400,6 +405,209 @@
EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
}
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
+
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(
+ baseTimeNs, configAddedTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()->second->
+ mAllMetricProducers[0]->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ // Event should not be kept.
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get());
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // This event should be kept. 1 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
+ nextPullTimeNs);
+
+ // This event should be kept. 2 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Event should not be kept. 2 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(2, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(1).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
+
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(
+ baseTimeNs, configAddedTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()->second->
+ mAllMetricProducers[0]->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 4);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
+ nextPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(1).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 4, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(2).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index b316562..e967eb3 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -28,7 +28,9 @@
namespace {
-StatsdConfig CreateStatsdConfig() {
+const int64_t metricId = 123456;
+
+StatsdConfig CreateStatsdConfig(bool useCondition = true) {
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto pulledAtomMatcher =
@@ -41,9 +43,11 @@
*config.add_predicate() = screenIsOffPredicate;
auto valueMetric = config.add_value_metric();
- valueMetric->set_id(123456);
+ valueMetric->set_id(metricId);
valueMetric->set_what(pulledAtomMatcher.id());
- valueMetric->set_condition(screenIsOffPredicate.id());
+ if (useCondition) {
+ valueMetric->set_condition(screenIsOffPredicate.id());
+ }
*valueMetric->mutable_value_field() =
CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
*valueMetric->mutable_dimensions_in_what() =
@@ -263,6 +267,99 @@
EXPECT_EQ(1, data.bucket_info(2).values_size());
}
+TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
+ auto config = CreateStatsdConfig(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(
+ baseTimeNs, configAddedTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()->second->
+ mAllMetricProducers[0]->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get());
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 0);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ // We have 1 full bucket, the two surrounding the activation are dropped.
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(0).values_size());
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 6286823..b9a5867 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -79,6 +79,8 @@
logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
+ gaugeProducer.prepareFistBucket();
+
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
@@ -124,6 +126,8 @@
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.prepareFistBucket();
+
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
@@ -207,6 +211,7 @@
logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ gaugeProducer.prepareFistBucket();
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -298,6 +303,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ gaugeProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -364,6 +370,7 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -424,6 +431,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ gaugeProducer.prepareFistBucket();
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -521,6 +529,7 @@
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ gaugeProducer.prepareFistBucket();
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -574,6 +583,7 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.prepareFistBucket();
Alert alert;
alert.set_id(101);
@@ -682,6 +692,7 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -766,6 +777,7 @@
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ gaugeProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 43a3c7b..0e82bad 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -105,6 +105,7 @@
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ valueProducer->prepareFistBucket();
return valueProducer;
}
@@ -124,6 +125,7 @@
new ValueMetricProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer->prepareFistBucket();
valueProducer->mCondition = ConditionState::kFalse;
return valueProducer;
}
@@ -167,6 +169,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, startTimeBase,
22, pullerManager);
+ valueProducer.prepareFistBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -196,6 +199,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, 5,
600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
+ valueProducer.prepareFistBucket();
EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, valueProducer.mCurrentBucketNum);
@@ -377,6 +381,7 @@
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ valueProducer->prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -665,6 +670,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -722,6 +728,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -772,6 +779,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -846,6 +854,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -888,6 +897,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
valueProducer.mCondition = ConditionState::kFalse;
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -962,6 +972,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -1258,6 +1269,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1302,6 +1314,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1348,6 +1361,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1398,6 +1412,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1443,6 +1458,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1516,6 +1532,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
+ valueProducer.prepareFistBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -2064,7 +2081,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
-
+ valueProducer.prepareFistBucket();
valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
@@ -2845,6 +2862,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
ProtoOutputStream output;
std::set<string> strSet;
@@ -2887,6 +2905,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -2950,6 +2969,7 @@
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
+ valueProducer.prepareFistBucket();
ProtoOutputStream output;
std::set<string> strSet;
@@ -2961,7 +2981,6 @@
EXPECT_EQ(1, report.value_metrics().data_size());
EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
- EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos());
}
TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 583103c..134ab10 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -140,6 +140,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
+import android.util.UtilConfig;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.ContextThemeWrapper;
@@ -6078,6 +6079,10 @@
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ // Let the util.*Array classes maintain "undefined" for apps targeting Pie or earlier.
+ UtilConfig.setThrowExceptionForUpperArrayOutOfBounds(
+ data.appInfo.targetSdkVersion >= Build.VERSION_CODES.Q);
+
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
// Prior to P, internal calls to decode Bitmaps used BitmapFactory,
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 49ba65f..6073354 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -30,6 +30,7 @@
import android.content.Context;
import android.database.Cursor;
import android.database.CursorWrapper;
+import android.database.DatabaseUtils;
import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
import android.net.Uri;
@@ -1258,55 +1259,50 @@
throw new SecurityException(displayName + " is not a valid filename");
}
- Query query = new Query().setFilterById(id);
- Cursor cursor = null;
- String oldDisplayName = null;
- String mimeType = null;
- try {
- cursor = query(query);
+ final String filePath;
+ final Query query = new Query().setFilterById(id);
+ try (Cursor cursor = query(query)) {
if (cursor == null) {
- return false;
+ throw new IllegalStateException("Missing cursor for download id=" + id);
}
if (cursor.moveToFirst()) {
- int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
- if (DownloadManager.STATUS_SUCCESSFUL != status) {
- return false;
+ final int status = cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_STATUS));
+ if (status != DownloadManager.STATUS_SUCCESSFUL) {
+ throw new IllegalStateException("Download is not completed yet: "
+ + DatabaseUtils.dumpCurrentRowToString(cursor));
}
- oldDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TITLE));
- mimeType = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_MEDIA_TYPE));
- }
- } finally {
- if (cursor != null) {
- cursor.close();
+ filePath = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_LOCAL_FILENAME));
+ if (filePath == null) {
+ throw new IllegalStateException("Download doesn't have a valid file path: "
+ + DatabaseUtils.dumpCurrentRowToString(cursor));
+ } else if (!new File(filePath).exists()) {
+ throw new IllegalStateException("Downloaded file doesn't exist anymore: "
+ + DatabaseUtils.dumpCurrentRowToString(cursor));
+ }
+ } else {
+ throw new IllegalStateException("Missing download id=" + id);
}
}
- if (oldDisplayName == null || mimeType == null) {
- throw new IllegalStateException(
- "Document with id " + id + " does not exist");
- }
-
- final File parent = Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOWNLOADS);
-
- final File before = new File(parent, oldDisplayName);
- final File after = new File(parent, displayName);
+ final File before = new File(filePath);
+ final File after = new File(before.getParentFile(), displayName);
if (after.exists()) {
- throw new IllegalStateException("Already exists " + after);
+ throw new IllegalStateException("File already exists: " + after);
}
if (!before.renameTo(after)) {
- throw new IllegalStateException("Failed to rename to " + after);
+ throw new IllegalStateException(
+ "Failed to rename file from " + before + " to " + after);
}
- ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_TITLE, displayName);
values.put(Downloads.Impl._DATA, after.toString());
values.putNull(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
- long[] ids = {id};
+ final long[] ids = { id };
- return (mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
- getWhereArgsForIds(ids)) == 1);
+ return mResolver.update(
+ mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids)) == 1;
}
/**
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index bcd43a2..6677587 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -125,15 +125,14 @@
public static final int RESULT_ALTERNATE = 1;
/**
- * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)}
- *
* Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
* if enrolled) for the current user of the device. The caller is expected to launch this
* activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
* {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
*
* @return the intent for launching the activity or null if no password is required.
- **/
+ * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)}
+ */
@Deprecated
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
public Intent createConfirmDeviceCredentialIntent(CharSequence title,
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index db23cfa..7f60b9c 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -363,18 +363,6 @@
boolean isNetworkActive();
/**
- * Setup a new physical network.
- * @param permission PERMISSION_NONE if no permissions required to access this network.
- * PERMISSION_NETWORK or PERMISSION_SYSTEM to set respective permission.
- */
- void createPhysicalNetwork(int netId, int permission);
-
- /**
- * Setup a new VPN.
- */
- void createVirtualNetwork(int netId, boolean secure);
-
- /**
* Add an interface to a network.
*/
void addInterfaceToNetwork(String iface, int netId);
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index e2af6f5..7653c77 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -449,11 +449,17 @@
/**
* Return the key at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the key stored at the given index.
*/
public K keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -462,11 +468,17 @@
/**
* Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value stored at the given index.
*/
public V valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -475,12 +487,18 @@
/**
* Set the value at a given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @param value The new value to store at this index.
* @return Returns the previous value at the given index.
*/
public V setValueAt(int index, V value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -673,11 +691,17 @@
/**
* Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value that was stored at this index.
*/
public V removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 4bd43d0..610641d 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -356,11 +356,17 @@
/**
* Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value stored at the given index.
*/
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -527,11 +533,17 @@
/**
* Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value that was stored at this index.
*/
public E removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index e4de704..698b5b0 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -142,9 +142,14 @@
/**
* Removes the mapping at the specified index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -235,9 +240,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -258,10 +268,15 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -276,9 +291,14 @@
* Given an index in the range <code>0...size()-1</code>, sets a new
* value for the <code>index</code>th key-value mapping that this
* LongSparseArray stores.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, E value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index f167f00..b7c3e18 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -170,9 +170,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -189,9 +194,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 67dfb02..7a8c780 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -169,10 +169,12 @@
* Removes the mapping at the specified index.
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -281,10 +283,12 @@
* key.</p>
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -307,11 +311,13 @@
* associated with the largest key.</p>
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -327,10 +333,13 @@
* value for the <code>index</code>th key-value mapping that this
* SparseArray stores.
*
- * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined.</p>
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, E value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 03fa1c9..5574047 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -166,9 +166,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -185,9 +190,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public boolean valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -196,9 +206,14 @@
/**
* Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, boolean value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index c68dc4e..84f9269 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -170,9 +170,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -189,9 +194,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -200,9 +210,14 @@
/**
* Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, int value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 37a9202..00e39a9 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -180,9 +180,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -199,9 +204,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/UtilConfig.java b/core/java/android/util/UtilConfig.java
new file mode 100644
index 0000000..7658c40
--- /dev/null
+++ b/core/java/android/util/UtilConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * Class to configure several of the util classes.
+ *
+ * @hide
+ */
+public class UtilConfig {
+ static boolean sThrowExceptionForUpperArrayOutOfBounds = true;
+
+ public static void setThrowExceptionForUpperArrayOutOfBounds(boolean check) {
+ sThrowExceptionForUpperArrayOutOfBounds = check;
+ }
+}
diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java
index 1360815..c8b7e25e 100644
--- a/core/java/android/view/DisplayAddress.java
+++ b/core/java/android/view/DisplayAddress.java
@@ -32,13 +32,12 @@
* A physical display ID is stable if the display can be identified using EDID information.
*
* @param physicalDisplayId A physical display ID.
- * @return The {@link Physical} address, or {@code null} if the ID is not stable.
+ * @return The {@link Physical} address.
* @see SurfaceControl#getPhysicalDisplayIds
*/
- @Nullable
+ @NonNull
public static Physical fromPhysicalDisplayId(long physicalDisplayId) {
- final Physical address = new Physical(physicalDisplayId);
- return address.getModel() == 0 ? null : address;
+ return new Physical(physicalDisplayId);
}
/**
@@ -59,9 +58,12 @@
* of a display. The port, located in the least significant byte, uniquely identifies a physical
* connector on the device for display output like eDP or HDMI. The model, located in the upper
* bits, uniquely identifies a display model across manufacturers by encoding EDID information.
+ * While the port is always stable, the model may not be available if EDID identification is not
+ * supported by the platform, in which case the address is not unique.
*/
public static final class Physical extends DisplayAddress {
- private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8;
+ private static final long UNKNOWN_MODEL = 0;
+ private static final int MODEL_SHIFT = 8;
private static final int PORT_MASK = 0xFF;
private final long mPhysicalDisplayId;
@@ -75,9 +77,13 @@
/**
* Model identifier unique across manufacturers.
+ *
+ * @return The model ID, or {@code null} if the model cannot be identified.
*/
- public long getModel() {
- return mPhysicalDisplayId >>> PHYSICAL_DISPLAY_ID_MODEL_SHIFT;
+ @Nullable
+ public Long getModel() {
+ final long model = mPhysicalDisplayId >>> MODEL_SHIFT;
+ return model == UNKNOWN_MODEL ? null : model;
}
@Override
@@ -88,11 +94,15 @@
@Override
public String toString() {
- return new StringBuilder("{")
- .append("port=").append(getPort() & PORT_MASK)
- .append(", model=0x").append(Long.toHexString(getModel()))
- .append("}")
- .toString();
+ final StringBuilder builder = new StringBuilder("{")
+ .append("port=").append(getPort() & PORT_MASK);
+
+ final Long model = getModel();
+ if (model != null) {
+ builder.append(", model=0x").append(Long.toHexString(model));
+ }
+
+ return builder.append("}").toString();
}
@Override
@@ -109,7 +119,7 @@
mPhysicalDisplayId = physicalDisplayId;
}
- public static final @android.annotation.NonNull Parcelable.Creator<Physical> CREATOR =
+ public static final @NonNull Parcelable.Creator<Physical> CREATOR =
new Parcelable.Creator<Physical>() {
@Override
public Physical createFromParcel(Parcel in) {
@@ -153,7 +163,7 @@
mMacAddress = macAddress;
}
- public static final @android.annotation.NonNull Parcelable.Creator<Network> CREATOR =
+ public static final @NonNull Parcelable.Creator<Network> CREATOR =
new Parcelable.Creator<Network>() {
@Override
public Network createFromParcel(Parcel in) {
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index dc2e6d5..0df2c83 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -459,6 +459,7 @@
optional bool is_charging = 1;
optional bool is_in_parole = 2;
+ optional int64 elapsed_realtime = 6;
// List of UIDs currently in the foreground.
repeated int32 foreground_uids = 3;
@@ -478,6 +479,16 @@
}
repeated TrackedJob tracked_jobs = 4;
+ message AlarmListener {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Whether the listener is waiting for an alarm or not.
+ optional bool is_waiting = 1;
+ // The time at which the alarm should go off, in the elapsed realtime timebase. Only
+ // valid if is_waiting is true.
+ optional int64 trigger_time_elapsed = 2;
+ }
+
message ExecutionStats {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -567,6 +578,8 @@
repeated TimingSession saved_sessions = 3;
repeated ExecutionStats execution_stats = 4;
+
+ optional AlarmListener in_quota_alarm_listener = 5;
}
repeated PackageStats package_stats = 5;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4c7f503..489a08a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2380,6 +2380,12 @@
<!-- ============================= -->
<eat-comment />
+ <!-- Removed View attributes without a specified format (b/131100106) -->
+ <attr name="__removed3" />
+ <attr name="__removed4" />
+ <attr name="__removed5" />
+ <attr name="__removed6" />
+
<!-- Attributes that can be used with {@link android.view.View} or
any of its subclasses. Also see {@link #ViewGroup_Layout} for
attributes that are processed by the view's parent. -->
@@ -4722,7 +4728,7 @@
<!-- Style (normal, bold, italic, bold|italic) for the text. -->
<attr name="textStyle" />
<!-- Weight for the font used in the TextView. -->
- <attr name="textFontWeight" />
+ <attr name="textFontWeight" format="integer"/>
<!-- Font family (named by string or as a font resource reference) for the text. -->
<attr name="fontFamily" />
<!-- Specifies the {@link android.os.LocaleList} for the text in this TextView.
@@ -8018,7 +8024,7 @@
<attr name="supportsAmbientMode" format="boolean" />
<!-- Uri that specifies a settings Slice for this wallpaper. -->
- <attr name="settingsSliceUri" />
+ <attr name="settingsSliceUri" format="string"/>
<!-- Indicates that this wallpaper service can support multiple engines to render on each
surface independently. An example use case is a multi-display set-up where the
@@ -8242,7 +8248,7 @@
<!-- The activity to launch when the setting is clicked on. -->
<attr name="settingsActivity"/>
<!-- The user restriction for this preference. -->
- <attr name="userRestriction"/>
+ <attr name="userRestriction" format="string"/>
</declare-styleable>
<!-- =============================== -->
@@ -8900,7 +8906,7 @@
<attr name="layout_ignoreOffset" format="boolean" />
<attr name="layout_gravity" />
<attr name="layout_hasNestedScrollIndicator" format="boolean" />
- <attr name="layout_maxHeight" />
+ <attr name="layout_maxHeight" format="dimension"/>
</declare-styleable>
<!-- @hide -->
@@ -9110,4 +9116,6 @@
<attr name="magnifierHorizontalOffset" format="dimension" />
<attr name="magnifierColorOverlay" format="color" />
</declare-styleable>
+
+ <attr name="autoSizePresetSizes" />
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 26a9f57..f9c9c53 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1690,14 +1690,14 @@
<attr name="usesNonSdkApi" />
<!-- If {@code true} the user is prompted to keep the app's data on uninstall -->
- <attr name="hasFragileUserData" />
+ <attr name="hasFragileUserData" format="boolean"/>
<attr name="zygotePreloadName" />
<!-- If {@code true} the system will clear app's data if a restore operation fails.
This flag is turned on by default. <em>This attribute is usable only by system apps.
</em> -->
- <attr name="allowClearUserDataOnFailedRestore"/>
+ <attr name="allowClearUserDataOnFailedRestore" format="boolean"/>
<!-- If {@code true} the app's non sensitive audio can be captured by other apps with
{@link android.media.AudioPlaybackCaptureConfiguration} and a
{@link android.media.projection.MediaProjection}.
@@ -1755,7 +1755,7 @@
<attr name="banner" />
<attr name="logo" />
<attr name="permissionGroup" />
- <attr name="backgroundPermission" />
+ <attr name="backgroundPermission" format="string"/>
<attr name="description" />
<attr name="request" />
<attr name="protectionLevel" />
@@ -1785,10 +1785,10 @@
<attr name="banner" />
<attr name="logo" />
<attr name="description" />
- <attr name="request" />
- <attr name="requestDetail" />
- <attr name="backgroundRequest" />
- <attr name="backgroundRequestDetail" />
+ <attr name="request" format="string"/>
+ <attr name="requestDetail" format="string"/>
+ <attr name="backgroundRequest" format="string"/>
+ <attr name="backgroundRequestDetail" format="string"/>
<attr name="permissionGroupFlags" />
<attr name="priority" />
</declare-styleable>
@@ -2254,7 +2254,7 @@
<attr name="path" />
<attr name="pathPrefix" />
<attr name="pathPattern" />
- <attr name="pathAdvancedPattern" />
+ <attr name="pathAdvancedPattern" format="string"/>
<attr name="permission" />
<attr name="readPermission" />
<attr name="writePermission" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index dbbe1b4..485add9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -35,6 +35,11 @@
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.captiveportallogin">
+ <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+ <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
+ </privapp-permissions>
+
<privapp-permissions package="com.android.cellbroadcastreceiver">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
@@ -213,6 +218,7 @@
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
<permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
<permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index c6c2fdd..c09bd79 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -89,15 +89,33 @@
<h4>Raw Audio Buffers</h4>
<p>
Raw audio buffers contain entire frames of PCM audio data, which is one sample for each channel
- in channel order. Each sample is a {@linkplain AudioFormat#ENCODING_PCM_16BIT 16-bit signed
- integer in native byte order}.
+ in channel order. Each PCM audio sample is either a 16 bit signed integer or a float,
+ in native byte order.
+ Raw audio buffers in the float PCM encoding are only possible
+ if the MediaFormat's {@linkplain MediaFormat#KEY_PCM_ENCODING}
+ is set to {@linkplain AudioFormat#ENCODING_PCM_FLOAT} during MediaCodec
+ {@link #configure configure(…)}
+ and confirmed by {@link #getOutputFormat} for decoders
+ or {@link #getInputFormat} for encoders.
+ A sample method to check for float PCM in the MediaFormat is as follows:
<pre class=prettyprint>
+ static boolean isPcmFloat(MediaFormat format) {
+ return format.getInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT)
+ == AudioFormat.ENCODING_PCM_FLOAT;
+ }</pre>
+
+ In order to extract, in a short array,
+ one channel of a buffer containing 16 bit signed integer audio data,
+ the following code may be used:
+
+ <pre class=prettyprint>
+ // Assumes the buffer PCM encoding is 16 bit.
short[] getSamplesForChannel(MediaCodec codec, int bufferId, int channelIx) {
ByteBuffer outputBuffer = codec.getOutputBuffer(bufferId);
MediaFormat format = codec.getOutputFormat(bufferId);
ShortBuffer samples = outputBuffer.order(ByteOrder.nativeOrder()).asShortBuffer();
- int numChannels = formet.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ int numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
if (channelIx < 0 || channelIx >= numChannels) {
return null;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index a687c14..35c691d 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -3145,6 +3145,93 @@
maxBlocks, maxBlocksPerSecond,
8 /* blockWidth */, 8 /* blockHeight */,
1 /* widthAlignment */, 1 /* heightAlignment */);
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
+ maxBlocksPerSecond = 829440;
+ maxBlocks = 36864;
+ maxBps = 200000;
+ int maxDim = 512;
+
+ // Sample rate, Picture Size, Bit rate and luma dimension for AV1 Codec,
+ // corresponding to the definitions in
+ // "AV1 Bitstream & Decoding Process Specification", Annex A
+ // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
+ for (CodecProfileLevel profileLevel: profileLevels) {
+ long SR = 0; // luma sample rate
+ int FS = 0; // luma picture size
+ int BR = 0; // bit rate kbps
+ int D = 0; // luma D
+ switch (profileLevel.level) {
+ case CodecProfileLevel.AV1Level2:
+ SR = 5529600; FS = 147456; BR = 1500; D = 2048; break;
+ case CodecProfileLevel.AV1Level21:
+ case CodecProfileLevel.AV1Level22:
+ case CodecProfileLevel.AV1Level23:
+ SR = 10454400; FS = 278784; BR = 3000; D = 2816; break;
+
+ case CodecProfileLevel.AV1Level3:
+ SR = 24969600; FS = 665856; BR = 6000; D = 4352; break;
+ case CodecProfileLevel.AV1Level31:
+ case CodecProfileLevel.AV1Level32:
+ case CodecProfileLevel.AV1Level33:
+ SR = 39938400; FS = 1065024; BR = 10000; D = 5504; break;
+
+ case CodecProfileLevel.AV1Level4:
+ SR = 77856768; FS = 2359296; BR = 12000; D = 6144; break;
+ case CodecProfileLevel.AV1Level41:
+ case CodecProfileLevel.AV1Level42:
+ case CodecProfileLevel.AV1Level43:
+ SR = 155713536; FS = 2359296; BR = 20000; D = 6144; break;
+
+ case CodecProfileLevel.AV1Level5:
+ SR = 273715200; FS = 8912896; BR = 30000; D = 8192; break;
+ case CodecProfileLevel.AV1Level51:
+ SR = 547430400; FS = 8912896; BR = 40000; D = 8192; break;
+ case CodecProfileLevel.AV1Level52:
+ SR = 1094860800; FS = 8912896; BR = 60000; D = 8192; break;
+ case CodecProfileLevel.AV1Level53:
+ SR = 1176502272; FS = 8912896; BR = 60000; D = 8192; break;
+
+ case CodecProfileLevel.AV1Level6:
+ SR = 1176502272; FS = 35651584; BR = 60000; D = 16384; break;
+ case CodecProfileLevel.AV1Level61:
+ SR = 2189721600L; FS = 35651584; BR = 100000; D = 16384; break;
+ case CodecProfileLevel.AV1Level62:
+ SR = 4379443200L; FS = 35651584; BR = 160000; D = 16384; break;
+ case CodecProfileLevel.AV1Level63:
+ SR = 4706009088L; FS = 35651584; BR = 160000; D = 16384; break;
+
+ default:
+ Log.w(TAG, "Unrecognized level "
+ + profileLevel.level + " for " + mime);
+ errors |= ERROR_UNRECOGNIZED;
+ }
+ switch (profileLevel.profile) {
+ case CodecProfileLevel.AV1ProfileMain8:
+ case CodecProfileLevel.AV1ProfileMain10:
+ case CodecProfileLevel.AV1ProfileMain10HDR10:
+ case CodecProfileLevel.AV1ProfileMain10HDR10Plus:
+ break;
+ default:
+ Log.w(TAG, "Unrecognized profile "
+ + profileLevel.profile + " for " + mime);
+ errors |= ERROR_UNRECOGNIZED;
+ }
+ errors &= ~ERROR_NONE_SUPPORTED;
+ maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
+ maxBlocks = Math.max(FS, maxBlocks);
+ maxBps = Math.max(BR * 1000, maxBps);
+ maxDim = Math.max(D, maxDim);
+ }
+
+ final int blockSize = 8;
+ int maxLengthInBlocks = Utils.divUp(maxDim, blockSize);
+ maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
+ maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
+ applyMacroBlockLimits(
+ maxLengthInBlocks, maxLengthInBlocks,
+ maxBlocks, maxBlocksPerSecond,
+ blockSize, blockSize,
+ 1 /* widthAlignment */, 1 /* heightAlignment */);
} else {
Log.w(TAG, "Unsupported mime " + mime);
// using minimal bitrate here. should be overriden by
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index 355bdd8..9add247 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
<uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index ea29ebb..12b41ca 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -485,10 +485,7 @@
mNotificationListAtBottomAtTimeOfTouch = false;
}
- boolean handled = false;
- if (mNotificationListAtBottomAtTimeOfTouch && mNotificationListAtBottom) {
- handled = closeGestureDetector.onTouchEvent(event);
- }
+ boolean handled = closeGestureDetector.onTouchEvent(event);
boolean isTracking = mIsTracking;
Rect rect = mNotificationList.getClipBounds();
float clippedHeight = 0;
@@ -1037,8 +1034,18 @@
GestureDetector.SimpleOnGestureListener {
@Override
+ public boolean onSingleTapUp(MotionEvent motionEvent) {
+ animateNotificationPanel(DEFAULT_FLING_VELOCITY, true);
+ return false;
+ }
+
+ @Override
public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
float distanceY) {
+ if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
+ return false;
+ }
+ // should not clip while scroll to the bottom of the list.
if (!mNotificationListAtBottomAtTimeOfTouch) {
return false;
}
@@ -1074,7 +1081,9 @@
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
-
+ if (!mNotificationListAtBottomAtTimeOfTouch && !mNotificationListAtBottom) {
+ return false;
+ }
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
|| Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
// swipe was not vertical or was not fast enough
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index d41aa6d..6840f9c 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -64,7 +64,7 @@
<item msgid="8719029132154020716">"ເປີດໃຊ້ແລ້ວ"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
- <item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
+ <item msgid="5347678900838034763">"AVRCP 1.4 (ຄ່າເລີ່ມຕົ້ນ)"</item>
<item msgid="2809759619990248160">"AVRCP 1.3"</item>
<item msgid="6199178154704729352">"AVRCP 1.5"</item>
<item msgid="5172170854953034852">"AVRCP 1.6"</item>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 48bcbd4..6121f03 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -214,8 +214,8 @@
<string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM திறத்தலை அனுமதிக்கவா?"</string>
<string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"எச்சரிக்கை: இந்த அமைப்பு இயக்கப்பட்டிருக்கும்போது, சாதன பாதுகாப்பு அம்சங்கள் இந்தச் சாதனத்தில் இயங்காது."</string>
<string name="mock_location_app" msgid="7966220972812881854">"போலி இருப்பிடப் பயன்பாட்டைத் தேர்ந்தெடு"</string>
- <string name="mock_location_app_not_set" msgid="809543285495344223">"போலி இருப்பிடப் பயன்பாடு அமைக்கப்படவில்லை"</string>
- <string name="mock_location_app_set" msgid="8966420655295102685">"போலி இருப்பிடப் பயன்பாடு: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="mock_location_app_not_set" msgid="809543285495344223">"போலி இருப்பிடப் ஆப்ஸ் அமைக்கப்படவில்லை"</string>
+ <string name="mock_location_app_set" msgid="8966420655295102685">"போலி இருப்பிடப் ஆப்ஸ்: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="7044075693643009662">"நெட்வொர்க்கிங்"</string>
<string name="wifi_display_certification" msgid="8611569543791307533">"வயர்லெஸ் காட்சிக்கான சான்றிதழ்"</string>
<string name="wifi_verbose_logging" msgid="4203729756047242344">"வைஃபை அதிவிவர நுழைவை இயக்கு"</string>
@@ -270,17 +270,17 @@
<string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"பெயர்கள் இல்லாத புளூடூத் சாதனங்கள் (MAC முகவரிகள் மட்டும்) காட்டப்படும்"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string>
<string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string>
- <string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் பயன்பாட்டை இயக்கு"</string>
+ <string name="enable_terminal_summary" msgid="67667852659359206">"அக ஷெல் அணுகலை வழங்கும் இறுதிப் ஆப்ஸை இயக்கு"</string>
<string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP சரிபார்ப்பு"</string>
<string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP சரிபார்க்கும் செயல்பாடுகளை அமை"</string>
<string name="debug_debugging_category" msgid="6781250159513471316">"பிழைதிருத்தம்"</string>
<string name="debug_app" msgid="8349591734751384446">"பிழைத்திருத்தப் பயன்பாட்டைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="debug_app_not_set" msgid="718752499586403499">"பிழைத்திருத்தப் பயன்பாடு அமைக்கப்படவில்லை"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"பிழைதிருத்தும் பயன்பாடு: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"பிழைத்திருத்தப் ஆப்ஸ் அமைக்கப்படவில்லை"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"பிழைதிருத்தும் ஆப்ஸ்: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="5156029161289091703">"பயன்பாட்டைத் தேர்ந்தெடுக்கவும்"</string>
<string name="no_application" msgid="2813387563129153880">"ஒன்றுமில்லை"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"பிழைதிருத்திக்குக் காத்திருக்கவும்"</string>
- <string name="wait_for_debugger_summary" msgid="1766918303462746804">"பிழைதிருத்தப்பட்ட பயன்பாடு செயல்படுவதற்கு முன்பு பிழைதிருத்தியை இணைப்பதற்குக் காத்திருக்கிறது"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"பிழைதிருத்தப்பட்ட ஆப்ஸ் செயல்படுவதற்கு முன்பு பிழைதிருத்தியை இணைப்பதற்குக் காத்திருக்கிறது"</string>
<string name="debug_input_category" msgid="1811069939601180246">"உள்ளீடு"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"வரைபொருள்"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"வன்பொருள் முடுக்கத்துடன் கூடிய காட்சியாக்கம்"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index aad9e79..4c72f48 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -77,6 +77,8 @@
<!-- Summary for the remembered network. -->
<string name="wifi_remembered">Saved</string>
+ <!-- Summary for the disconnected network. [CHAR LIMIT=40] -->
+ <string name="wifi_disconnected">Disconnected</string>
<!-- Status for networks disabled for unknown reason -->
<string name="wifi_disabled_generic">Disabled</string>
<!-- Status for networked disabled from a DNS or DHCP failure -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 34d11b5..02bcc09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -968,6 +968,13 @@
}
public String getSettingsSummary() {
+ return getSettingsSummary(false /*convertSavedAsDisconnected*/);
+ }
+
+ /**
+ * Returns the summary for the AccessPoint.
+ */
+ public String getSettingsSummary(boolean convertSavedAsDisconnected) {
// Update to new summary
StringBuilder summary = new StringBuilder();
@@ -1033,8 +1040,13 @@
R.string.wifi_ap_unable_to_handle_new_sta));
break;
default:
- // "Saved"
- summary.append(mContext.getString(R.string.wifi_remembered));
+ if (convertSavedAsDisconnected) {
+ // Disconnected
+ summary.append(mContext.getString(R.string.wifi_disconnected));
+ } else {
+ // "Saved"
+ summary.append(mContext.getString(R.string.wifi_remembered));
+ }
break;
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 8e40271..af4704c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -516,6 +516,30 @@
}
@Test
+ public void testSummaryString_showsDisconnected() {
+ AccessPoint ap = createAccessPointWithScanResultCache();
+ ap.update(new WifiConfiguration());
+
+ assertThat(ap.getSettingsSummary(true /*convertSavedAsDisconnected*/))
+ .isEqualTo(mContext.getString(R.string.wifi_disconnected));
+ }
+
+ @Test
+ public void testSummaryString_concatenatedMeteredAndDisconnected() {
+ AccessPoint ap = createAccessPointWithScanResultCache();
+ WifiConfiguration config = new WifiConfiguration();
+ config.meteredHint = true;
+ ap.update(config);
+
+ String expectedString =
+ mContext.getResources().getString(R.string.preference_summary_default_combination,
+ mContext.getString(R.string.wifi_metered_label),
+ mContext.getString(R.string.wifi_disconnected));
+ assertThat(ap.getSettingsSummary(true /*convertSavedAsDisconnected*/))
+ .isEqualTo(expectedString);
+ }
+
+ @Test
public void testSummaryString_showsConnectedViaSuggestionOrSpecifierApp() throws Exception {
final int rssi = -55;
final String appPackageName = "com.test.app";
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 2e9b03c..12d1f7c 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -27,6 +27,7 @@
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
+import android.os.SystemProperties;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -40,6 +41,7 @@
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -70,6 +72,8 @@
private Context mContext;
private CharSequence mSeparator;
private WakefulnessLifecycle mWakefulnessLifecycle;
+ @VisibleForTesting
+ protected boolean mDisplayOpportunisticSubscriptionCarrierText;
private final WakefulnessLifecycle.Observer mWakefulnessObserver =
new WakefulnessLifecycle.Observer() {
@Override
@@ -247,7 +251,6 @@
}
/**
- * STOPSHIP(b/130246708) remove when no longer needed for testing purpose.
* @param subscriptions
*/
private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
@@ -274,21 +277,40 @@
}
}
+ /**
+ * updates if opportunistic sub carrier text should be displayed or not
+ *
+ */
+ @VisibleForTesting
+ public void updateDisplayOpportunisticSubscriptionCarrierText() {
+ mDisplayOpportunisticSubscriptionCarrierText = SystemProperties
+ .getBoolean(TelephonyProperties
+ .DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME, false);
+ }
+
+ protected List<SubscriptionInfo> getSubscriptionInfo() {
+ List<SubscriptionInfo> subs;
+ if (mDisplayOpportunisticSubscriptionCarrierText) {
+ SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext
+ .getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE));
+ subs = subscriptionManager.getActiveSubscriptionInfoList(false);
+ if (subs == null) {
+ subs = new ArrayList<>();
+ } else {
+ filterMobileSubscriptionInSameGroup(subs);
+ }
+ } else {
+ subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+ }
+ return subs;
+ }
+
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
CharSequence displayText = null;
-
- // STOPSHIP(b/130246708) revert to mKeyguardUpdateMonitor.getSubscriptionInfo(false).
- SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext.getSystemService(
- Context.TELEPHONY_SUBSCRIPTION_SERVICE));
- List<SubscriptionInfo> subs = subscriptionManager.getActiveSubscriptionInfoList(false);
-
- if (subs == null) {
- subs = new ArrayList<>();
- } else {
- filterMobileSubscriptionInSameGroup(subs);
- }
+ List<SubscriptionInfo> subs = getSubscriptionInfo();
final int numSubs = subs.size();
final int[] subsIds = new int[numSubs];
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 20de4d1..8d62bca 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -9,12 +9,14 @@
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
+import android.os.Build;
import android.transition.ChangeBounds;
import android.transition.Transition;
import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.transition.TransitionValues;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
import android.util.TypedValue;
import android.view.View;
@@ -47,6 +49,8 @@
*/
public class KeyguardClockSwitch extends RelativeLayout {
+ private static final String TAG = "KeyguardClockSwitch";
+
/**
* Controller used to track StatusBar state to know when to show the big_clock_container.
*/
@@ -343,6 +347,10 @@
if (mClockPlugin != null) {
mClockPlugin.onTimeTick();
}
+ if (Build.IS_DEBUGGABLE) {
+ // Log for debugging b/130888082 (sysui waking up, but clock not updating)
+ Log.d(TAG, "Updating clock: " + mClockView.getText());
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 5860230..420d0fa 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -249,7 +249,7 @@
mContext.getResources()
.getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
if (mCurrentDialog.requiresConfirmation()) {
- mCurrentDialog.showConfirmationButton(true /* show */);
+ mCurrentDialog.updateState(BiometricDialogView.STATE_PENDING_CONFIRMATION);
} else {
mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
mHandler.postDelayed(() -> {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 30c97d7..32a7678 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -95,7 +95,7 @@
private Bundle mBundle;
- private int mLastState;
+ private int mState;
private boolean mAnimatingAway;
private boolean mWasForceRemoved;
private boolean mSkipIntro;
@@ -209,7 +209,11 @@
setDismissesDialog(rightSpace);
mNegativeButton.setOnClickListener((View v) -> {
- mCallback.onNegativePressed();
+ if (mState == STATE_PENDING_CONFIRMATION || mState == STATE_AUTHENTICATED) {
+ mCallback.onUserCanceled();
+ } else {
+ mCallback.onNegativePressed();
+ }
});
mPositiveButton.setOnClickListener((View v) -> {
@@ -260,7 +264,7 @@
mDialog.getLayoutParams().width = (int) mDialogWidth;
}
- mLastState = STATE_IDLE;
+ mState = STATE_IDLE;
updateState(STATE_AUTHENTICATING);
CharSequence titleText = mBundle.getCharSequence(BiometricPrompt.KEY_TITLE);
@@ -288,6 +292,11 @@
mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
+ if (requiresConfirmation()) {
+ mPositiveButton.setVisibility(View.VISIBLE);
+ mPositiveButton.setEnabled(false);
+ }
+
if (mWasForceRemoved || mSkipIntro) {
// Show the dialog immediately
mLayout.animate().cancel();
@@ -327,7 +336,7 @@
private void setDismissesDialog(View v) {
v.setClickable(true);
v.setOnTouchListener((View view, MotionEvent event) -> {
- if (mLastState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
+ if (mState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
mCallback.onUserCanceled();
}
return true;
@@ -406,16 +415,6 @@
return mRequireConfirmation;
}
- public void showConfirmationButton(boolean show) {
- if (show) {
- mHandler.removeMessages(MSG_CLEAR_MESSAGE);
- updateState(STATE_PENDING_CONFIRMATION);
- mPositiveButton.setVisibility(View.VISIBLE);
- } else {
- mPositiveButton.setVisibility(View.GONE);
- }
- }
-
public void setUserId(int userId) {
mUserId = userId;
}
@@ -452,15 +451,21 @@
public void updateState(int newState) {
if (newState == STATE_PENDING_CONFIRMATION) {
+ mHandler.removeMessages(MSG_CLEAR_MESSAGE);
mErrorText.setVisibility(View.INVISIBLE);
+ mPositiveButton.setEnabled(true);
} else if (newState == STATE_AUTHENTICATED) {
mPositiveButton.setVisibility(View.GONE);
mNegativeButton.setVisibility(View.GONE);
mErrorText.setVisibility(View.INVISIBLE);
}
- updateIcon(mLastState, newState);
- mLastState = newState;
+ if (newState == STATE_PENDING_CONFIRMATION || newState == STATE_AUTHENTICATED) {
+ mNegativeButton.setText(R.string.cancel);
+ }
+
+ updateIcon(mState, newState);
+ mState = newState;
}
public void showTryAgainButton(boolean show) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index d269686..28156da 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -293,6 +293,12 @@
mTryAgainButton.setVisibility(View.GONE);
}
}
+
+ if (show) {
+ mPositiveButton.setVisibility(View.GONE);
+ } else if (!show && requiresConfirmation()) {
+ mPositiveButton.setVisibility(View.VISIBLE);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index c886062..21f0c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.wakelock.SettableWakeLock;
@@ -69,7 +70,8 @@
/**
* Controls the indications and error messages shown on the Keyguard
*/
-public class KeyguardIndicationController implements StateListener {
+public class KeyguardIndicationController implements StateListener,
+ UnlockMethodCache.OnUnlockMethodChangedListener {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -81,6 +83,9 @@
private final Context mContext;
private final ShadeController mShadeController;
private final AccessibilityController mAccessibilityController;
+ private final UnlockMethodCache mUnlockMethodCache;
+ private final StatusBarStateController mStatusBarStateController;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private ViewGroup mIndicationArea;
private KeyguardIndicationTextView mTextView;
private KeyguardIndicationTextView mDisclosure;
@@ -122,18 +127,21 @@
this(context, indicationArea, lockIcon, new LockPatternUtils(context),
WakeLock.createPartial(context, "Doze:KeyguardIndication"),
Dependency.get(ShadeController.class),
- Dependency.get(AccessibilityController.class));
-
- registerCallbacks(KeyguardUpdateMonitor.getInstance(context));
+ Dependency.get(AccessibilityController.class),
+ UnlockMethodCache.getInstance(context),
+ Dependency.get(StatusBarStateController.class),
+ KeyguardUpdateMonitor.getInstance(context));
}
/**
- * Creates a new KeyguardIndicationController for testing. Does *not* register callbacks.
+ * Creates a new KeyguardIndicationController for testing.
*/
@VisibleForTesting
KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
LockPatternUtils lockPatternUtils, WakeLock wakeLock, ShadeController shadeController,
- AccessibilityController accessibilityController) {
+ AccessibilityController accessibilityController, UnlockMethodCache unlockMethodCache,
+ StatusBarStateController statusBarStateController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor) {
mContext = context;
mIndicationArea = indicationArea;
mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
@@ -143,6 +151,9 @@
mLockIcon = lockIcon;
mShadeController = shadeController;
mAccessibilityController = accessibilityController;
+ mUnlockMethodCache = unlockMethodCache;
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
// lock icon is not used on all form factors.
if (mLockIcon != null) {
mLockIcon.setOnLongClickListener(this::handleLockLongClick);
@@ -161,15 +172,12 @@
mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
-
updateDisclosure();
- }
- private void registerCallbacks(KeyguardUpdateMonitor monitor) {
- monitor.registerCallback(getKeyguardCallback());
-
- KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mTickReceiver);
- Dependency.get(StatusBarStateController.class).addCallback(this);
+ mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
+ mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
+ mStatusBarStateController.addCallback(this);
+ mUnlockMethodCache.addListener(this);
}
/**
@@ -179,8 +187,10 @@
* //TODO: This can probably be converted to a fragment and not have to be manually recreated
*/
public void destroy() {
- KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mTickReceiver);
- Dependency.get(StatusBarStateController.class).removeCallback(this);
+ mKeyguardUpdateMonitor.removeCallback(mTickReceiver);
+ mKeyguardUpdateMonitor.removeCallback(getKeyguardCallback());
+ mStatusBarStateController.removeCallback(this);
+ mUnlockMethodCache.removeListener(this);
}
private boolean handleLockLongClick(View view) {
@@ -271,7 +281,8 @@
*
* @return {@code null} or an empty string if a trust indication text should not be shown.
*/
- private String getTrustGrantedIndication() {
+ @VisibleForTesting
+ String getTrustGrantedIndication() {
return mContext.getString(R.string.keyguard_indication_trust_unlocked);
}
@@ -363,7 +374,6 @@
return;
}
- KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
int userId = KeyguardUpdateMonitor.getCurrentUser();
String trustGrantedIndication = getTrustGrantedIndication();
String trustManagedIndication = getTrustManagedIndication();
@@ -374,7 +384,7 @@
mTextView.switchIndication(mTransientIndication);
mTextView.setTextColor(mTransientTextColorState);
} else if (!TextUtils.isEmpty(trustGrantedIndication)
- && updateMonitor.getUserHasTrust(userId)) {
+ && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mTextView.switchIndication(trustGrantedIndication);
mTextView.setTextColor(mInitialTextColorState);
} else if (mPowerPluggedIn) {
@@ -389,8 +399,8 @@
mTextView.switchIndication(indication);
}
} else if (!TextUtils.isEmpty(trustManagedIndication)
- && updateMonitor.getUserTrustIsManaged(userId)
- && !updateMonitor.getUserHasTrust(userId)) {
+ && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
+ && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
mTextView.switchIndication(trustManagedIndication);
mTextView.setTextColor(mInitialTextColorState);
} else {
@@ -572,6 +582,11 @@
setDozing(isDozing);
}
+ @Override
+ public void onUnlockMethodStateChanged() {
+ updateIndication(!mDozing);
+ }
+
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 9f91a17..212c8f5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -66,9 +66,17 @@
private static final CharSequence SEPARATOR = " \u2014 ";
private static final String TEST_CARRIER = "TEST_CARRIER";
+ private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
+ private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
+ private static final int TEST_CARRIER_ID = 1;
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
- DATA_ROAMING_DISABLE, null, null, null, null, false, null, "");
+ DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
+ TEST_CARRIER_ID, 0);
+ private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(0, "", 0,
+ TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
+ TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
@@ -369,6 +377,33 @@
captor.getValue().carrierText);
}
+ @Test
+ public void testCarrierText_GroupedSubWithOpportunisticCarrierText() {
+ reset(mCarrierTextCallback);
+ List<SubscriptionInfo> list = new ArrayList<>();
+ list.add(TEST_SUBSCRIPTION);
+ list.add(TEST_SUBSCRIPTION_2);
+ when(mKeyguardUpdateMonitor.getSimState(anyInt()))
+ .thenReturn(IccCardConstants.State.READY);
+ when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
+ mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText();
+
+ // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
+ // same answer as KeyguardUpdateMonitor. Remove when this is addressed
+ when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+
+ ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
+ ArgumentCaptor.forClass(
+ CarrierTextController.CarrierTextCallbackInfo.class);
+
+ mCarrierTextController.updateCarrierText();
+ mTestableLooper.processAllMessages();
+ verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
+
+ assertEquals(TEST_CARRIER_2, captor.getValue().carrierText);
+ }
+
public static class TestCarrierTextController extends CarrierTextController {
private KeyguardUpdateMonitor mKUM;
@@ -383,5 +418,10 @@
super.setListening(callback);
mKeyguardUpdateMonitor = mKUM;
}
+
+ @Override
+ public void updateDisplayOpportunisticSubscriptionCarrierText() {
+ mDisplayOpportunisticSubscriptionCarrierText = true;
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 375b6e54..ac536a5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -20,10 +20,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -43,12 +45,15 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.UnlockMethodCache;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -81,6 +86,12 @@
private ShadeController mShadeController;
@Mock
private AccessibilityController mAccessibilityController;
+ @Mock
+ private UnlockMethodCache mUnlockMethodCache;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private KeyguardIndicationTextView mTextView;
private KeyguardIndicationController mController;
@@ -111,7 +122,8 @@
Looper.prepare();
}
mController = new KeyguardIndicationController(mContext, mIndicationArea, mLockIcon,
- mLockPatternUtils, mWakeLock, mShadeController, mAccessibilityController);
+ mLockPatternUtils, mWakeLock, mShadeController, mAccessibilityController,
+ mUnlockMethodCache, mStatusBarStateController, mKeyguardUpdateMonitor);
}
@Test
@@ -250,4 +262,32 @@
longClickCaptor.getValue().onLongClick(mLockIcon);
verify(mLockPatternUtils).requireCredentialEntry(anyInt());
}
+
+ @Test
+ public void unlockMethodCache_listenerUpdatesIndication() {
+ createController();
+ String restingIndication = "Resting indication";
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+ mController.setRestingIndication(restingIndication);
+ mController.setVisible(true);
+ assertThat(mTextView.getText()).isEqualTo(mController.getTrustGrantedIndication());
+
+ reset(mKeyguardUpdateMonitor);
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
+ mController.onUnlockMethodStateChanged();
+ assertThat(mTextView.getText()).isEqualTo(restingIndication);
+ }
+
+ @Test
+ public void unlockMethodCache_listener() {
+ createController();
+ verify(mUnlockMethodCache).addListener(eq(mController));
+ verify(mStatusBarStateController).addCallback(eq(mController));
+ verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
+
+ mController.destroy();
+ verify(mUnlockMethodCache).removeListener(eq(mController));
+ verify(mStatusBarStateController).removeCallback(eq(mController));
+ verify(mKeyguardUpdateMonitor, times(2)).removeCallback(any());
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f5710e3..55f9826 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3071,11 +3071,7 @@
// fallback network the default or requested a new network from the
// NetworkFactories, so network traffic isn't interrupted for an unnecessarily
// long time.
- try {
- mNetd.networkDestroy(nai.network.netId);
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception destroying network: " + e);
- }
+ destroyNativeNetwork(nai);
mDnsManager.removeNetwork(nai.network);
}
synchronized (mNetworkForNetId) {
@@ -3083,6 +3079,35 @@
}
}
+ private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+ try {
+ // This should never fail. Specifying an already in use NetID will cause failure.
+ if (networkAgent.isVPN()) {
+ mNetd.networkCreateVpn(networkAgent.network.netId,
+ (networkAgent.networkMisc == null
+ || !networkAgent.networkMisc.allowBypass));
+ } else {
+ mNetd.networkCreatePhysical(networkAgent.network.netId,
+ getNetworkPermission(networkAgent.networkCapabilities));
+ }
+ mDnsResolver.createNetworkCache(networkAgent.network.netId);
+ return true;
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Error creating network " + networkAgent.network.netId + ": "
+ + e.getMessage());
+ return false;
+ }
+ }
+
+ private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+ try {
+ mNetd.networkDestroy(networkAgent.network.netId);
+ mDnsResolver.destroyNetworkCache(networkAgent.network.netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception destroying network: " + e);
+ }
+ }
+
// If this method proves to be too slow then we can maintain a separate
// pendingIntent => NetworkRequestInfo map.
// This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
@@ -6476,21 +6501,7 @@
// A network that has just connected has zero requests and is thus a foreground network.
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
- try {
- // This should never fail. Specifying an already in use NetID will cause failure.
- if (networkAgent.isVPN()) {
- mNMS.createVirtualNetwork(networkAgent.network.netId,
- (networkAgent.networkMisc == null ||
- !networkAgent.networkMisc.allowBypass));
- } else {
- mNMS.createPhysicalNetwork(networkAgent.network.netId,
- getNetworkPermission(networkAgent.networkCapabilities));
- }
- } catch (Exception e) {
- loge("Error creating network " + networkAgent.network.netId + ": "
- + e.getMessage());
- return;
- }
+ if (!createNativeNetwork(networkAgent)) return;
networkAgent.created = true;
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b1aaa82..8d76634 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2051,28 +2051,6 @@
}
@Override
- public void createPhysicalNetwork(int netId, int permission) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.networkCreatePhysical(netId, permission);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void createVirtualNetwork(int netId, boolean secure) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.networkCreateVpn(netId, secure);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
public void addInterfaceToNetwork(String iface, int netId) {
modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fc5d393..11ddceb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -543,7 +543,7 @@
private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
- final OomAdjuster mOomAdjuster;
+ OomAdjuster mOomAdjuster;
final LowMemDetector mLowMemDetector;
/** All system services */
@@ -1483,7 +1483,7 @@
final ServiceThread mProcStartHandlerThread;
final Handler mProcStartHandler;
- final ActivityManagerConstants mConstants;
+ ActivityManagerConstants mConstants;
// Encapsulates the global setting "hidden_api_blacklist_exemptions"
final HiddenApiSettings mHiddenApiBlacklist;
diff --git a/services/core/java/com/android/server/am/OomAdjProfiler.java b/services/core/java/com/android/server/am/OomAdjProfiler.java
index 71f0db5..9846b31 100644
--- a/services/core/java/com/android/server/am/OomAdjProfiler.java
+++ b/services/core/java/com/android/server/am/OomAdjProfiler.java
@@ -29,6 +29,9 @@
import java.io.PrintWriter;
public class OomAdjProfiler {
+ // Disable profiling for Q. Re-enable once b/130635979 is fixed.
+ private static final boolean PROFILING_DISABLED = true;
+
@GuardedBy("this")
private boolean mOnBattery;
@GuardedBy("this")
@@ -56,6 +59,9 @@
final RingBuffer<CpuTimes> mSystemServerCpuTimesHist = new RingBuffer<>(CpuTimes.class, 10);
void batteryPowerChanged(boolean onBattery) {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
scheduleSystemServerCpuTimeUpdate();
mOnBattery = onBattery;
@@ -63,6 +69,9 @@
}
void onWakefulnessChanged(int wakefulness) {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
scheduleSystemServerCpuTimeUpdate();
mScreenOff = wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -70,6 +79,9 @@
}
void oomAdjStarted() {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
mOomAdjStartTimeMs = SystemClock.currentThreadTimeMillis();
mOomAdjStarted = true;
@@ -77,6 +89,9 @@
}
void oomAdjEnded() {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
if (!mOomAdjStarted) {
return;
@@ -86,6 +101,9 @@
}
private void scheduleSystemServerCpuTimeUpdate() {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
if (mSystemServerCpuTimeUpdateScheduled) {
return;
@@ -98,6 +116,9 @@
}
private void updateSystemServerCpuTime(boolean onBattery, boolean screenOff) {
+ if (PROFILING_DISABLED) {
+ return;
+ }
final long cpuTimeMs = mProcessCpuTracker.getCpuTimeForPid(Process.myPid());
synchronized (this) {
mSystemServerCpuTime.addCpuTimeMs(
@@ -121,6 +142,9 @@
}
void dump(PrintWriter pw) {
+ if (PROFILING_DISABLED) {
+ return;
+ }
synchronized (this) {
if (mSystemServerCpuTimeUpdateScheduled) {
while (mSystemServerCpuTimeUpdateScheduled) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 8ae7c7d..043daef 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -75,6 +75,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -1897,6 +1898,10 @@
// For apps that sit around for a long time in the interactive state, we need
// to report this at least once a day so they don't go idle.
maybeUpdateUsageStatsLocked(app, nowElapsed);
+ } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
+ > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
+ // For foreground services that sit around for a long time but are not interacted with.
+ maybeUpdateUsageStatsLocked(app, nowElapsed);
}
if (changes != 0) {
@@ -1917,6 +1922,14 @@
return success;
}
+ // ONLY used for unit testing in OomAdjusterTests.java
+ @VisibleForTesting
+ void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) {
+ synchronized (mService) {
+ maybeUpdateUsageStatsLocked(app, nowElapsed);
+ }
+ }
+
@GuardedBy("mService")
private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
if (DEBUG_USAGE_STATS) {
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index e33392d..2321afb 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -263,12 +263,6 @@
}
public void removeNetwork(Network network) {
- try {
- mDnsResolver.clearResolverConfiguration(network.netId);
- } catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error clearing DNS configuration: " + e);
- return;
- }
mPrivateDnsMap.remove(network.netId);
mPrivateDnsValidationMap.remove(network.netId);
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c2aade3..651ce7d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2037,6 +2037,12 @@
if (mCurSeq <= 0) mCurSeq = 1;
mCurClient = cs;
mCurInputContext = inputContext;
+ if (cs.selfReportedDisplayId != displayIdToShowIme) {
+ // CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
+ // InputConnection#requestCursorUpdates() is not implemented in the application so that
+ // IMEs will always receive false from this API.
+ missingMethods |= MissingMethodFlags.REQUEST_CURSOR_UPDATES;
+ }
mCurInputContextMissingMethods = missingMethods;
mCurAttribute = attribute;
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index ccd1db4..11f0939 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -511,17 +511,28 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ final int userId = jobStatus.getSourceUserId();
+ final String pkgName = jobStatus.getSourcePackageName();
// Still need to track jobs even if mShouldThrottle is false in case it's set to true at
// some point.
- ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
- jobStatus.getSourcePackageName());
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
if (jobs == null) {
jobs = new ArraySet<>();
- mTrackedJobs.add(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), jobs);
+ mTrackedJobs.add(userId, pkgName, jobs);
}
jobs.add(jobStatus);
jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
- jobStatus.setQuotaConstraintSatisfied(!mShouldThrottle || isWithinQuotaLocked(jobStatus));
+ if (mShouldThrottle) {
+ final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
+ jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
+ if (!isWithinQuota) {
+ maybeScheduleStartAlarmLocked(userId, pkgName,
+ getEffectiveStandbyBucket(jobStatus));
+ }
+ } else {
+ // QuotaController isn't throttling, so always set to true.
+ jobStatus.setQuotaConstraintSatisfied(true);
+ }
}
@Override
@@ -1628,6 +1639,9 @@
if (isActive()) {
pw.print("started at ");
pw.print(mStartTimeElapsed);
+ pw.print(" (");
+ pw.print(sElapsedRealtimeClock.millis() - mStartTimeElapsed);
+ pw.print("ms ago)");
} else {
pw.print("NOT active");
}
@@ -1937,6 +1951,7 @@
pw.println("Is throttling: " + mShouldThrottle);
pw.println("Is charging: " + mChargeTracker.isCharging());
pw.println("In parole: " + mInParole);
+ pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
pw.println();
pw.print("Foreground UIDs: ");
@@ -2030,6 +2045,26 @@
}
}
pw.decreaseIndent();
+
+ pw.println();
+ pw.println("In quota alarms:");
+ pw.increaseIndent();
+ for (int u = 0; u < mInQuotaAlarmListeners.numUsers(); ++u) {
+ final int userId = mInQuotaAlarmListeners.keyAt(u);
+ for (int p = 0; p < mInQuotaAlarmListeners.numPackagesForUser(userId); ++p) {
+ final String pkgName = mInQuotaAlarmListeners.keyAt(u, p);
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.valueAt(u, p);
+
+ pw.print(string(userId, pkgName));
+ pw.print(": ");
+ if (alarmListener.isWaiting()) {
+ pw.println(alarmListener.getTriggerTimeElapsed());
+ } else {
+ pw.println("NOT WAITING");
+ }
+ }
+ }
+ pw.decreaseIndent();
}
@Override
@@ -2040,6 +2075,8 @@
proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
+ proto.write(StateControllerProto.QuotaController.ELAPSED_REALTIME,
+ sElapsedRealtimeClock.millis());
for (int i = 0; i < mForegroundUids.size(); ++i) {
proto.write(StateControllerProto.QuotaController.FOREGROUND_UIDS,
@@ -2132,6 +2169,18 @@
}
}
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, pkgName);
+ if (alarmListener != null) {
+ final long alToken = proto.start(
+ StateControllerProto.QuotaController.PackageStats.IN_QUOTA_ALARM_LISTENER);
+ proto.write(StateControllerProto.QuotaController.AlarmListener.IS_WAITING,
+ alarmListener.isWaiting());
+ proto.write(
+ StateControllerProto.QuotaController.AlarmListener.TRIGGER_TIME_ELAPSED,
+ alarmListener.getTriggerTimeElapsed());
+ proto.end(alToken);
+ }
+
proto.end(psToken);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index da836c2..1b705bb 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -189,6 +189,7 @@
private final LockPatternUtils mLockPatternUtils;
private final NotificationManager mNotificationManager;
private final UserManager mUserManager;
+ private final IStorageManager mStorageManager;
private final IActivityManager mActivityManager;
private final SyntheticPasswordManager mSpManager;
@@ -460,6 +461,7 @@
mStorage = injector.getStorage();
mNotificationManager = injector.getNotificationManager();
mUserManager = injector.getUserManager();
+ mStorageManager = injector.getStorageManager();
mStrongAuthTracker = injector.getStrongAuthTracker();
mStrongAuthTracker.register(mStrongAuth);
@@ -1186,6 +1188,14 @@
}
}
+ /**
+ * Unlock the user (both storage and user state) and its associated managed profiles
+ * synchronously.
+ *
+ * <em>Be very careful about the risk of deadlock here: ActivityManager.unlockUser()
+ * can end up calling into other system services to process user unlock request (via
+ * {@link com.android.server.SystemServiceManager#unlockUser} </em>
+ */
private void unlockUser(int userId, byte[] token, byte[] secret) {
// TODO: make this method fully async so we can update UI with progress strings
final CountDownLatch latch = new CountDownLatch(1);
@@ -1639,13 +1649,27 @@
}
}
+ private boolean isUserKeyUnlocked(int userId) {
+ try {
+ return mStorageManager.isUserKeyUnlocked(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to check user key locked state", e);
+ return false;
+ }
+ }
+
+ /** Unlock disk encryption */
+ private void unlockUserKey(int userId, byte[] token, byte[] secret) throws RemoteException {
+ final UserInfo userInfo = mUserManager.getUserInfo(userId);
+ mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
+ }
+
private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
throws RemoteException {
final UserInfo userInfo = mUserManager.getUserInfo(userId);
- final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
- storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
+ mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -1654,10 +1678,9 @@
private void fixateNewestUserKeyAuth(int userId)
throws RemoteException {
if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
- final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
- storageManager.fixateNewestUserKeyAuth(userId);
+ mStorageManager.fixateNewestUserKeyAuth(userId);
} finally {
Binder.restoreCallingIdentity(callingId);
}
@@ -2571,7 +2594,7 @@
credential, credentialType, auth, requestedQuality, userId);
final Map<Integer, byte[]> profilePasswords;
if (credential != null) {
- // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
+ // not needed by synchronizeUnifiedWorkChallengeForProfiles()
profilePasswords = null;
if (mSpManager.hasSidForUser(userId)) {
@@ -2599,9 +2622,12 @@
mSpManager.clearSidForUser(userId);
getGateKeeperService().clearSecureUserId(userId);
// Clear key from vold so ActivityManager can just unlock the user with empty secret
- // during boot.
+ // during boot. Vold storage needs to be unlocked before manipulation of the keys can
+ // succeed.
+ unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
clearUserKeyProtection(userId);
fixateNewestUserKeyAuth(userId);
+ unlockKeystore(auth.deriveKeyStorePassword(), userId);
setKeystorePassword(null, userId);
}
setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
@@ -2809,45 +2835,50 @@
if (!mSpManager.hasEscrowData(userId)) {
throw new SecurityException("Escrow token is disabled on the current user");
}
- result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
+ result = setLockCredentialWithTokenInternalLocked(credential, type, tokenHandle, token,
requestedQuality, userId);
}
if (result) {
synchronized (mSeparateChallengeLock) {
setSeparateProfileChallengeEnabledLocked(userId, true, null);
}
+ if (credential == null) {
+ // If clearing credential, unlock the user manually in order to progress user start
+ // Call unlockUser() on a handler thread so no lock is held (either by LSS or by
+ // the caller like DPMS), otherwise it can lead to deadlock.
+ mHandler.post(() -> unlockUser(userId, null, null));
+ }
notifyPasswordChanged(userId);
notifySeparateProfileChallengeChanged(userId);
}
return result;
}
- private boolean setLockCredentialWithTokenInternal(byte[] credential, int type,
- long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
+ @GuardedBy("mSpManager")
+ private boolean setLockCredentialWithTokenInternalLocked(byte[] credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId)
+ throws RemoteException {
final AuthenticationResult result;
- synchronized (mSpManager) {
- result = mSpManager.unwrapTokenBasedSyntheticPassword(
- getGateKeeperService(), tokenHandle, token, userId);
- if (result.authToken == null) {
- Slog.w(TAG, "Invalid escrow token supplied");
- return false;
- }
- if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
- // Most likely, an untrusted credential reset happened in the past which
- // changed the synthetic password
- Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
- + "verification.");
- return false;
- }
- // Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
- // called by setLockCredentialWithAuthTokenLocked().
- // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
- setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
- long oldHandle = getSyntheticPasswordHandleLocked(userId);
- setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
- requestedQuality, userId);
- mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
+ result = mSpManager.unwrapTokenBasedSyntheticPassword(
+ getGateKeeperService(), tokenHandle, token, userId);
+ if (result.authToken == null) {
+ Slog.w(TAG, "Invalid escrow token supplied");
+ return false;
}
+ if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
+ // Most likely, an untrusted credential reset happened in the past which
+ // changed the synthetic password
+ Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
+ + "verification.");
+ return false;
+ }
+ // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
+ setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
+ long oldHandle = getSyntheticPasswordHandleLocked(userId);
+ setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
+ requestedQuality, userId);
+ mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
+
onAuthTokenKnownForUser(userId, result.authToken);
return true;
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index ee22264..a5d59e3 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -260,6 +260,10 @@
return false;
}
} else {
+ if (!mOld.isEmpty()) {
+ getOutPrintWriter().println("Old password provided but user has no password");
+ return false;
+ }
return true;
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e2033c6..21a862a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4816,10 +4816,11 @@
NotificationRecord oldRecord) {
Notification notification = r.getNotification();
- // Does the app want to bubble & have permission to bubble?
+ // Does the app want to bubble & is able to bubble
boolean canBubble = notification.getBubbleMetadata() != null
&& mPreferencesHelper.areBubblesAllowed(pkg, userId)
- && r.getChannel().canBubble();
+ && r.getChannel().canBubble()
+ && !mActivityManager.isLowRamDevice();
// Is the app in the foreground?
final boolean appIsForeground =
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 9ede263..d45a8ef 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -922,6 +922,8 @@
permissionsState.setGlobalGids(mGlobalGids);
synchronized (mLock) {
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
+
final int N = pkg.requestedPermissions.size();
for (int i = 0; i < N; i++) {
final String permName = pkg.requestedPermissions.get(i);
@@ -943,6 +945,17 @@
continue;
}
+ // Cache newImplicitPermissions before modifing permissionsState as for the shared
+ // uids the original and new state are the same object
+ if (!origPermissions.hasRequestedPermission(permName)
+ && pkg.implicitPermissions.contains(permName)) {
+ newImplicitPermissions.add(permName);
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+ }
+ }
+
// Limit ephemeral apps to ephemeral allowed permissions.
if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
if (DEBUG_PERMISSIONS) {
@@ -1298,7 +1311,7 @@
updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
- permissionsState, pkg, updatedUserIds);
+ permissionsState, pkg, newImplicitPermissions, updatedUserIds);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -1437,27 +1450,9 @@
private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
@NonNull PermissionsState origPs,
@NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull ArraySet<String> newImplicitPermissions,
@NonNull int[] updatedUserIds) {
String pkgName = pkg.packageName;
- ArraySet<String> newImplicitPermissions = new ArraySet<>();
-
- int numRequestedPerms = pkg.requestedPermissions.size();
- for (int i = 0; i < numRequestedPerms; i++) {
- BasePermission bp = mSettings.getPermissionLocked(pkg.requestedPermissions.get(i));
- if (bp != null) {
- String perm = bp.getName();
-
- if (!origPs.hasRequestedPermission(perm) && pkg.implicitPermissions.contains(
- perm)) {
- newImplicitPermissions.add(perm);
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, perm + " is newly added for " + pkgName);
- }
- }
- }
- }
-
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 05e9b93..c272707 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -11,6 +11,9 @@
},
{
"include-filter": "android.permission.cts.PermissionFlagsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.SharedUidPermissionsTest"
}
]
},
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index f492d13..7c30f25 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -2197,4 +2197,51 @@
assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
verify(handler, never()).sendMessageDelayed(any(), anyInt());
}
+
+ /**
+ * Tests that the start alarm is properly scheduled when a job has been throttled due to the job
+ * count quota.
+ */
+ @Test
+ public void testStartAlarmScheduled_JobCount_AllowedTime() {
+ // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+ // because it schedules an alarm too. Prevent it from doing so.
+ spyOn(mQuotaController);
+ doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+ final long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final int standbyBucket = WORKING_INDEX;
+ setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+ // No sessions saved yet.
+ mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
+ standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Ran jobs up to the job limit. All of them should be allowed to run.
+ for (int i = 0; i < mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) {
+ JobStatus job = createJobStatus("testStartAlarmScheduled_JobCount_AllowedTime", i);
+ mQuotaController.maybeStartTrackingJobLocked(job, null);
+ assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ mQuotaController.prepareForExecutionLocked(job);
+ advanceElapsedClock(SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ advanceElapsedClock(SECOND_IN_MILLIS);
+ }
+ // Start alarm shouldn't have been scheduled since the app was in quota up until this point.
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // The app is now out of job count quota
+ JobStatus throttledJob = createJobStatus(
+ "testStartAlarmScheduled_JobCount_AllowedTime", 42);
+ mQuotaController.maybeStartTrackingJobLocked(throttledJob, null);
+ assertFalse(throttledJob.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
+ SOURCE_PACKAGE, standbyBucket);
+ final long expectedWorkingAlarmTime =
+ stats.jobCountExpirationTimeElapsed + mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
new file mode 100644
index 0000000..d3bcff5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.app.ActivityManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
+
+import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerService;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test class for {@link OomAdjuster}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:OomAdjusterTests
+ */
+public class OomAdjusterTests {
+ private static Context sContext;
+ private static ActivityManagerService sService;
+
+ private ProcessRecord mProcessRecord;
+
+ private static final long ZERO = 0L;
+ private static final long USAGE_STATS_INTERACTION = 2 * 60 * 60 * 1000L;
+ private static final long SERVICE_USAGE_INTERACTION = 30 * 60 * 1000;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ sContext = getInstrumentation().getTargetContext();
+
+ // We need to run with dexmaker share class loader to make use of
+ // ActivityTaskManagerService from wm package.
+ runWithDexmakerShareClassLoader(() -> {
+ sService = mock(ActivityManagerService.class);
+ sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
+ sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
+ sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal();
+
+ sService.mConstants = new ActivityManagerConstants(sContext, sService,
+ sContext.getMainThreadHandler());
+ sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null);
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+ LocalServices.addService(UsageStatsManagerInternal.class,
+ mock(UsageStatsManagerInternal.class));
+ sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
+ });
+ }
+
+ @Before
+ public void setUpProcess() {
+ // Need to run with dexmaker share class loader to mock package private class.
+ runWithDexmakerShareClassLoader(() -> {
+ mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(),
+ "name", 12345));
+ });
+
+ // Ensure certain services and constants are defined properly
+ assertNotNull(sService.mUsageStatsService);
+ assertEquals(USAGE_STATS_INTERACTION, sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL);
+ assertEquals(SERVICE_USAGE_INTERACTION, sService.mConstants.SERVICE_USAGE_INTERACTION_TIME);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStatePersistentUI() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateTop() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
+ mProcessRecord.reportedInteraction = true;
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval() {
+ final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
+ mProcessRecord.reportedInteraction = true;
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateBoundTop() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateFGS() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(elapsedTime, false, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction() {
+ final long elapsedTime = ZERO;
+ final long fgInteractionTime = 1000L;
+ mProcessRecord.setFgInteractionTime(fgInteractionTime);
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(fgInteractionTime, false, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction() {
+ final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
+ final long fgInteractionTime = 1000L;
+ mProcessRecord.setFgInteractionTime(fgInteractionTime);
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(fgInteractionTime, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction() {
+ final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
+ final long fgInteractionTime = 1000L;
+ mProcessRecord.setFgInteractionTime(fgInteractionTime);
+ mProcessRecord.reportedInteraction = true;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(fgInteractionTime, true, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateFGSLocation() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(elapsedTime, false, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateBFGS() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateImportantFG() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ mProcessRecord.reportedInteraction = true;
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval() {
+ final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ mProcessRecord.reportedInteraction = true;
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, true, elapsedTime);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateImportantBG() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, false, ZERO);
+ }
+
+ @Test
+ public void testMaybeUpdateUsageStats_ProcStateService() {
+ final long elapsedTime = ZERO;
+ mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE);
+ sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
+
+ assertProcessRecordState(ZERO, false, ZERO);
+ }
+
+ private void assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction,
+ long interactionEventTime) {
+ assertEquals("Foreground interaction time was not updated correctly.",
+ fgInteractionTime, mProcessRecord.getFgInteractionTime());
+ assertEquals("Interaction was not updated correctly.",
+ reportedInteraction, mProcessRecord.reportedInteraction);
+ assertEquals("Interaction event time was not updated correctly.",
+ interactionEventTime, mProcessRecord.getInteractionEventTime());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
index dbdb41b..1ae1fa6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
@@ -65,17 +65,13 @@
listener.onStarted(userId, null);
listener.onFinished(userId, null);
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
- if (secret != null) {
- if (auths.size() > 1) {
- throw new AssertionFailedError("More than one secret exists");
- }
- Pair<byte[], byte[]> auth = auths.get(0);
- if ((!mIgnoreBadUnlock) && auth.second != null && !Arrays.equals(secret, auth.second)) {
- throw new AssertionFailedError("Invalid secret to unlock user");
- }
- } else {
- if (auths != null && auths.size() > 0) {
- throw new AssertionFailedError("Cannot unlock encrypted user with empty token");
+ if (auths.size() > 1) {
+ throw new AssertionFailedError("More than one secret exists");
+ }
+ Pair<byte[], byte[]> auth = auths.get(0);
+ if (!Arrays.equals(secret, auth.second)) {
+ if (!mIgnoreBadUnlock) {
+ throw new AssertionFailedError("Invalid secret to unlock user " + userId);
}
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 34bb0a8..cbca087 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5154,4 +5154,41 @@
assertEquals(1, notifsAfter.length);
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
}
+
+ @Test
+ public void testNotificationBubbles_disabled_lowRamDevice() throws Exception {
+ // Bubbles are allowed!
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+ when(mPreferencesHelper.getNotificationChannel(
+ anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+ mTestNotificationChannel);
+ when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+ mTestNotificationChannel.getImportance());
+
+ // Plain notification that has bubble metadata
+ NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+ null /* tvExtender */, true /* isBubble */);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ // Would be a normal notification because wouldn't have met requirements to bubble
+ StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifsBefore.length);
+ assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
+
+ // Make the package foreground so that we're allowed to be a bubble
+ when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+ IMPORTANCE_FOREGROUND);
+
+ // And we are low ram
+ when(mActivityManager.isLowRamDevice()).thenReturn(true);
+
+ // We wouldn't be a bubble because the notification didn't meet requirements (low ram)
+ StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
+ assertEquals(1, notifsAfter.length);
+ assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
+
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 030c3f4..dd9b242 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -224,4 +224,11 @@
*/
static final String PROPERTY_VIDEOCALL_AUDIO_OUTPUT = "persist.radio.call.audio.output";
+ /** 'true' if the carrier text from opportunistic subscription should be used to display
+ * on UI.
+ *
+ */
+ String DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME =
+ "persist.radio.display_opportunistic_carrier";
+
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 16ec134..c15775f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4894,7 +4894,10 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
- // CS tells netd about the empty DNS config for this network.
+
+ verify(mMockDnsResolver, times(1)).createNetworkCache(
+ eq(mCellNetworkAgent.getNetwork().netId));
+ // CS tells dnsresolver about the empty DNS config for this network.
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
reset(mMockDnsResolver);
@@ -4978,6 +4981,8 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
+ verify(mMockDnsResolver, times(1)).createNetworkCache(
+ eq(mCellNetworkAgent.getNetwork().netId));
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
@@ -5851,12 +5856,17 @@
cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
reset(mNetworkManagementService);
reset(mMockDnsResolver);
+ reset(mMockNetd);
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
.thenReturn(getClatInterfaceConfig(myIpv4));
// Connect with ipv6 link properties. Expect prefix discovery to be started.
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
+
+ verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+ verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -6048,7 +6058,7 @@
verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
verify(mMockDnsResolver, times(1))
- .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
+ .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
// Disconnect wifi
ConditionVariable cv = waitForConnectivityBroadcasts(1);
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index fe401e2..c291b39 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1712,7 +1712,14 @@
child_ref.SetSource(item_source);
styleable->entries.push_back(std::move(child_ref));
- out_resource->child_resources.push_back(std::move(child_resource));
+ // Do not add referenced attributes that do not define a format to the table.
+ CHECK(child_resource.value != nullptr);
+ Attribute* attr = ValueCast<Attribute>(child_resource.value.get());
+
+ CHECK(attr != nullptr);
+ if (attr->type_mask != android::ResTable_map::TYPE_ANY) {
+ out_resource->child_resources.push_back(std::move(child_resource));
+ }
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
diag_->Error(DiagMessage(item_source) << "unknown tag <"
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 7c8b6d0..464225f 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -341,7 +341,7 @@
std::string input = R"(
<attr name="foo" />
<declare-styleable name="bar">
- <attr name="baz" />
+ <attr name="baz" format="reference"/>
</declare-styleable>)";
ASSERT_TRUE(TestParse(input, watch_config));
@@ -589,8 +589,7 @@
EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
- ASSERT_THAT(attr, NotNull());
- EXPECT_TRUE(attr->IsWeak());
+ ASSERT_THAT(attr, IsNull());
attr = test::GetValue<Attribute>(&table_, "attr/bat");
ASSERT_THAT(attr, NotNull());