Merge "Frameworks: Make MockUtils more robust" into pi-dev
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 133f33b..49de1ac 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -31,9 +31,8 @@
namespace os {
namespace statsd {
-// TODO: Get rid of bucketNumbers, and return to the original circular array method.
AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
- : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
+ : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.num_buckets() <= 0) {
ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
@@ -60,85 +59,102 @@
size_t AnomalyTracker::index(int64_t bucketNum) const {
if (bucketNum < 0) {
- // To support this use-case, we can easily modify index to wrap around. But currently
- // AnomalyTracker should never need this, so if it happens, it's a bug we should log.
- // TODO: Audit this.
ALOGE("index() was passed a negative bucket number (%lld)!", (long long)bucketNum);
}
return bucketNum % mNumOfPastBuckets;
}
-void AnomalyTracker::flushPastBuckets(const int64_t& latestPastBucketNum) {
- VLOG("addPastBucket() called.");
- if (latestPastBucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
- ALOGE("Cannot add a past bucket %lld units in past", (long long)latestPastBucketNum);
+void AnomalyTracker::advanceMostRecentBucketTo(const int64_t& bucketNum) {
+ VLOG("advanceMostRecentBucketTo() called.");
+ if (bucketNum <= mMostRecentBucketNum) {
+ ALOGW("Cannot advance buckets backwards (bucketNum=%lld but mMostRecentBucketNum=%lld)",
+ (long long)bucketNum, (long long)mMostRecentBucketNum);
return;
}
-
- // The past packets are ancient. Empty out old mPastBuckets[i] values and reset
- // mSumOverPastBuckets.
- if (latestPastBucketNum - mMostRecentBucketNum >= mNumOfPastBuckets) {
+ // If in the future (i.e. buckets are ancient), just empty out all past info.
+ if (bucketNum >= mMostRecentBucketNum + mNumOfPastBuckets) {
resetStorage();
- } else {
- for (int64_t i = std::max(0LL, (long long)(mMostRecentBucketNum - mNumOfPastBuckets + 1));
- i <= latestPastBucketNum - mNumOfPastBuckets; i++) {
- const int idx = index(i);
- subtractBucketFromSum(mPastBuckets[idx]);
- mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket.
+ mMostRecentBucketNum = bucketNum;
+ return;
+ }
+
+ // Clear out space by emptying out old mPastBuckets[i] values and update mSumOverPastBuckets.
+ for (int64_t i = mMostRecentBucketNum + 1; i <= bucketNum; i++) {
+ const int idx = index(i);
+ subtractBucketFromSum(mPastBuckets[idx]);
+ mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket.
+ }
+ mMostRecentBucketNum = bucketNum;
+}
+
+void AnomalyTracker::addPastBucket(const MetricDimensionKey& key,
+ const int64_t& bucketValue,
+ const int64_t& bucketNum) {
+ VLOG("addPastBucket(bucketValue) called.");
+ if (mNumOfPastBuckets == 0 ||
+ bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
+ return;
+ }
+
+ const int bucketIndex = index(bucketNum);
+ if (bucketNum <= mMostRecentBucketNum && (mPastBuckets[bucketIndex] != nullptr)) {
+ // We need to insert into an already existing past bucket.
+ std::shared_ptr<DimToValMap>& bucket = mPastBuckets[bucketIndex];
+ auto itr = bucket->find(key);
+ if (itr != bucket->end()) {
+ // Old entry already exists; update it.
+ subtractValueFromSum(key, itr->second);
+ itr->second = bucketValue;
+ } else {
+ bucket->insert({key, bucketValue});
}
- }
-
- // It is an update operation.
- if (latestPastBucketNum <= mMostRecentBucketNum &&
- latestPastBucketNum > mMostRecentBucketNum - mNumOfPastBuckets) {
- subtractBucketFromSum(mPastBuckets[index(latestPastBucketNum)]);
+ mSumOverPastBuckets[key] += bucketValue;
+ } else {
+ // Bucket does not exist yet (in future or was never made), so we must make it.
+ std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
+ bucket->insert({key, bucketValue});
+ addPastBucket(bucket, bucketNum);
}
}
-void AnomalyTracker::addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
+void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucket,
const int64_t& bucketNum) {
- if (mNumOfPastBuckets == 0) {
+ VLOG("addPastBucket(bucket) called.");
+ if (mNumOfPastBuckets == 0 ||
+ bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
return;
}
- flushPastBuckets(bucketNum);
- auto& bucket = mPastBuckets[index(bucketNum)];
- if (bucket == nullptr) {
- bucket = std::make_shared<DimToValMap>();
+ if (bucketNum <= mMostRecentBucketNum) {
+ // We are updating an old bucket, not adding a new one.
+ subtractBucketFromSum(mPastBuckets[index(bucketNum)]);
+ } else {
+ // Clear space for the new bucket to be at bucketNum.
+ advanceMostRecentBucketTo(bucketNum);
}
- bucket->insert({key, bucketValue});
+ mPastBuckets[index(bucketNum)] = bucket;
addBucketToSum(bucket);
- mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum);
-}
-
-void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucketValues,
- const int64_t& bucketNum) {
- VLOG("addPastBucket() called.");
- if (mNumOfPastBuckets == 0) {
- return;
- }
- flushPastBuckets(bucketNum);
- // Replace the oldest bucket with the new bucket we are adding.
- mPastBuckets[index(bucketNum)] = bucketValues;
- addBucketToSum(bucketValues);
- mMostRecentBucketNum = std::max(mMostRecentBucketNum, bucketNum);
}
void AnomalyTracker::subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket) {
if (bucket == nullptr) {
return;
}
- // For each dimension present in the bucket, subtract its value from its corresponding sum.
for (const auto& keyValuePair : *bucket) {
- auto itr = mSumOverPastBuckets.find(keyValuePair.first);
- if (itr == mSumOverPastBuckets.end()) {
- continue;
- }
- itr->second -= keyValuePair.second;
- // TODO: No need to look up the object twice like this. Use a var.
- if (itr->second == 0) {
- mSumOverPastBuckets.erase(itr);
- }
+ subtractValueFromSum(keyValuePair.first, keyValuePair.second);
+ }
+}
+
+
+void AnomalyTracker::subtractValueFromSum(const MetricDimensionKey& key,
+ const int64_t& bucketValue) {
+ auto itr = mSumOverPastBuckets.find(key);
+ if (itr == mSumOverPastBuckets.end()) {
+ return;
+ }
+ itr->second -= bucketValue;
+ if (itr->second == 0) {
+ mSumOverPastBuckets.erase(itr);
}
}
@@ -154,7 +170,8 @@
int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
const int64_t& bucketNum) const {
- if (mNumOfPastBuckets == 0 || bucketNum < 0) {
+ if (bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets
+ || bucketNum > mMostRecentBucketNum) {
return 0;
}
@@ -174,11 +191,13 @@
return 0;
}
-bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const MetricDimensionKey& key,
+bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
+ const MetricDimensionKey& key,
const int64_t& currentBucketValue) {
+
+ // currentBucketNum should be the next bucket after pastBuckets. If not, advance so that it is.
if (currentBucketNum > mMostRecentBucketNum + 1) {
- // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
- addPastBucket(key, 0, currentBucketNum - 1);
+ advanceMostRecentBucketTo(currentBucketNum - 1);
}
return mAlert.has_trigger_if_sum_gt() &&
getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
@@ -190,19 +209,17 @@
VLOG("Skipping anomaly declaration since within refractory period");
return;
}
- mRefractoryPeriodEndsSec[key] = (timestampNs / NS_PER_SEC) + mAlert.refractory_period_secs();
-
- // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
- // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) { resetStorage(); }
+ if (mAlert.has_refractory_period_secs()) {
+ mRefractoryPeriodEndsSec[key] = ((timestampNs + NS_PER_SEC - 1) / NS_PER_SEC) // round up
+ + mAlert.refractory_period_secs();
+ // TODO: If we had access to the bucket_size_millis, consider calling resetStorage()
+ // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) {resetStorage();}
+ }
if (!mSubscriptions.empty()) {
- if (mAlert.has_id()) {
- ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.", mAlert.id(),
- key.toString().c_str());
- informSubscribers(key);
- } else {
- ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
- }
+ ALOGI("An anomaly (%lld) %s has occurred! Informing subscribers.",
+ mAlert.id(), key.toString().c_str());
+ informSubscribers(key);
} else {
ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
}
@@ -227,7 +244,7 @@
const MetricDimensionKey& key) {
const auto& it = mRefractoryPeriodEndsSec.find(key);
if (it != mRefractoryPeriodEndsSec.end()) {
- if ((timestampNs / NS_PER_SEC) <= it->second) {
+ if (timestampNs < it->second * NS_PER_SEC) {
return true;
} else {
mRefractoryPeriodEndsSec.erase(key);
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index d27dee8..d3da7dc 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -47,20 +47,32 @@
mSubscriptions.push_back(subscription);
}
- // Adds a bucket.
- // Bucket index starts from 0.
- void addPastBucket(std::shared_ptr<DimToValMap> bucketValues, const int64_t& bucketNum);
+ // Adds a bucket for the given bucketNum (index starting at 0).
+ // If a bucket for bucketNum already exists, it will be replaced.
+ // Also, advances to bucketNum (if not in the past), effectively filling any intervening
+ // buckets with 0s.
+ void addPastBucket(std::shared_ptr<DimToValMap> bucket, const int64_t& bucketNum);
+
+ // Inserts (or replaces) the bucket entry for the given bucketNum at the given key to be the
+ // given bucketValue. If the bucket does not exist, it will be created.
+ // Also, advances to bucketNum (if not in the past), effectively filling any intervening
+ // buckets with 0s.
void addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
const int64_t& bucketNum);
- // Returns true if detected anomaly for the existing buckets on one or more dimension keys.
+ // Returns true if, based on past buckets plus the new currentBucketValue (which generally
+ // represents the partially-filled current bucket), an anomaly has happened.
+ // Also advances to currBucketNum-1.
bool detectAnomaly(const int64_t& currBucketNum, const MetricDimensionKey& key,
const int64_t& currentBucketValue);
// Informs incidentd about the detected alert.
void declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key);
- // Detects the alert and informs the incidentd when applicable.
+ // Detects if, based on past buckets plus the new currentBucketValue (which generally
+ // represents the partially-filled current bucket), an anomaly has happened, and if so,
+ // declares an anomaly and informs relevant subscribers.
+ // Also advances to currBucketNum-1.
void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
const MetricDimensionKey& key, const int64_t& currentBucketValue);
@@ -69,24 +81,26 @@
return; // Base AnomalyTracker class has no need for the AlarmMonitor.
}
- // Helper function to return the sum value of past buckets at given dimension.
+ // Returns the sum of all past bucket values for the given dimension key.
int64_t getSumOverPastBuckets(const MetricDimensionKey& key) const;
- // Helper function to return the value for a past bucket.
+ // Returns the value for a past bucket, or 0 if that bucket doesn't exist.
int64_t getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const;
- // Returns the anomaly threshold.
+ // Returns the anomaly threshold set in the configuration.
inline int64_t getAnomalyThreshold() const {
return mAlert.trigger_if_sum_gt();
}
- // Returns the refractory period timestamp (in seconds) for the given key.
+ // Returns the refractory period ending timestamp (in seconds) for the given key.
+ // Before this moment, any detected anomaly will be ignored.
// If there is no stored refractory period ending timestamp, returns 0.
uint32_t getRefractoryPeriodEndsSec(const MetricDimensionKey& key) const {
const auto& it = mRefractoryPeriodEndsSec.find(key);
return it != mRefractoryPeriodEndsSec.end() ? it->second : 0;
}
+ // Returns the (constant) number of past buckets this anomaly tracker can store.
inline int getNumOfPastBuckets() const {
return mNumOfPastBuckets;
}
@@ -112,22 +126,27 @@
// for the anomaly detection (since the current bucket is not in the past).
const int mNumOfPastBuckets;
- // The existing bucket list.
+ // Values for each of the past mNumOfPastBuckets buckets. Always of size mNumOfPastBuckets.
+ // mPastBuckets[i] can be null, meaning that no data is present in that bucket.
std::vector<shared_ptr<DimToValMap>> mPastBuckets;
- // Sum over all existing buckets cached in mPastBuckets.
+ // Cached sum over all existing buckets in mPastBuckets.
+ // Its buckets never contain entries of 0.
DimToValMap mSumOverPastBuckets;
// The bucket number of the last added bucket.
int64_t mMostRecentBucketNum = -1;
// Map from each dimension to the timestamp that its refractory period (if this anomaly was
- // declared for that dimension) ends, in seconds. Only anomalies that occur after this period
- // ends will be declared.
+ // declared for that dimension) ends, in seconds. From this moment and onwards, anomalies
+ // can be declared again.
// Entries may be, but are not guaranteed to be, removed after the period is finished.
unordered_map<MetricDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
- void flushPastBuckets(const int64_t& currBucketNum);
+ // Advances mMostRecentBucketNum to bucketNum, deleting any data that is now too old.
+ // Specifically, since it is now too old, removes the data for
+ // [mMostRecentBucketNum - mNumOfPastBuckets + 1, bucketNum - mNumOfPastBuckets].
+ void advanceMostRecentBucketTo(const int64_t& bucketNum);
// Add the information in the given bucket to mSumOverPastBuckets.
void addBucketToSum(const shared_ptr<DimToValMap>& bucket);
@@ -136,15 +155,21 @@
// and remove any items with value 0.
void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
+ // From mSumOverPastBuckets[key], subtracts bucketValue, removing it if it is now 0.
+ void subtractValueFromSum(const MetricDimensionKey& key, const int64_t& bucketValue);
+
+ // Returns true if in the refractory period, else false.
+ // If there is a stored refractory period but it ended prior to timestampNs, it is removed.
bool isInRefractoryPeriod(const uint64_t& timestampNs, const MetricDimensionKey& key);
// Calculates the corresponding bucket index within the circular array.
+ // Requires bucketNum >= 0.
size_t index(int64_t bucketNum) const;
// Resets all bucket data. For use when all the data gets stale.
virtual void resetStorage();
- // Informs the subscribers that an anomaly has occurred.
+ // Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred.
void informSubscribers(const MetricDimensionKey& key);
FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index 31d50be..d85157c 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -26,30 +26,13 @@
DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
const sp<AlarmMonitor>& alarmMonitor)
- : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
+ : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
+ VLOG("DurationAnomalyTracker() called");
}
DurationAnomalyTracker::~DurationAnomalyTracker() {
- stopAllAlarms();
-}
-
-void DurationAnomalyTracker::resetStorage() {
- AnomalyTracker::resetStorage();
- if (!mAlarms.empty()) VLOG("AnomalyTracker.resetStorage() called but mAlarms is NOT empty!");
-}
-
-void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
- const uint64_t& timestampNs) {
- auto itr = mAlarms.find(dimensionKey);
- if (itr == mAlarms.end()) {
- return;
- }
-
- if (itr->second != nullptr &&
- static_cast<uint32_t>(timestampNs / NS_PER_SEC) >= itr->second->timestampSec) {
- declareAnomaly(timestampNs, dimensionKey);
- stopAlarm(dimensionKey);
- }
+ VLOG("~DurationAnomalyTracker() called");
+ cancelAllAlarms();
}
void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
@@ -57,34 +40,47 @@
// Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely.
uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1)/ NS_PER_SEC) + 1; // round up
if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
+ // TODO: Bug! By the refractory's end, the data might be erased and the alarm inapplicable.
VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period");
timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1;
}
+
+ auto itr = mAlarms.find(dimensionKey);
+ if (itr != mAlarms.end() && mAlarmMonitor != nullptr) {
+ mAlarmMonitor->remove(itr->second);
+ }
+
sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec};
- mAlarms.insert({dimensionKey, alarm});
+ mAlarms[dimensionKey] = alarm;
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->add(alarm);
}
}
-void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey) {
- auto itr = mAlarms.find(dimensionKey);
- if (itr != mAlarms.end()) {
- mAlarms.erase(dimensionKey);
- if (mAlarmMonitor != nullptr) {
- mAlarmMonitor->remove(itr->second);
- }
+void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey,
+ const uint64_t& timestampNs) {
+ const auto itr = mAlarms.find(dimensionKey);
+ if (itr == mAlarms.end()) {
+ return;
+ }
+
+ // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now.
+ if (itr->second != nullptr && timestampNs >= NS_PER_SEC * itr->second->timestampSec) {
+ declareAnomaly(timestampNs, dimensionKey);
+ }
+ mAlarms.erase(dimensionKey);
+ if (mAlarmMonitor != nullptr) {
+ mAlarmMonitor->remove(itr->second);
}
}
-void DurationAnomalyTracker::stopAllAlarms() {
- std::set<MetricDimensionKey> keys;
- for (auto itr = mAlarms.begin(); itr != mAlarms.end(); ++itr) {
- keys.insert(itr->first);
+void DurationAnomalyTracker::cancelAllAlarms() {
+ if (mAlarmMonitor != nullptr) {
+ for (const auto& itr : mAlarms) {
+ mAlarmMonitor->remove(itr.second);
+ }
}
- for (auto key : keys) {
- stopAlarm(key);
- }
+ mAlarms.clear();
}
void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 51186df..92bb2bc 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -32,21 +32,20 @@
virtual ~DurationAnomalyTracker();
- // Starts the alarm at the given timestamp.
+ // Sets an alarm for the given timestamp.
+ // Replaces previous alarm if one already exists.
void startAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& eventTime);
// Stops the alarm.
- void stopAlarm(const MetricDimensionKey& dimensionKey);
+ // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
+ // declare the anomaly now.
+ void stopAlarm(const MetricDimensionKey& dimensionKey, const uint64_t& timestampNs);
- // Stop all the alarms owned by this tracker.
- void stopAllAlarms();
-
- // Declares the anomaly when the alarm expired given the current timestamp.
- void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey,
- const uint64_t& timestampNs);
+ // Stop all the alarms owned by this tracker. Does not declare any anomalies.
+ void cancelAllAlarms();
// Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
- // and removes it from firedAlarms.
+ // and removes it from firedAlarms. The AlarmMonitor is not informed.
// Note that this will generally be called from a different thread from the other functions;
// the caller is responsible for thread safety.
void informAlarmsFired(const uint64_t& timestampNs,
@@ -60,9 +59,6 @@
// Anomaly alarm monitor.
sp<AlarmMonitor> mAlarmMonitor;
- // Resets all bucket data. For use when all the data gets stale.
- void resetStorage() override;
-
FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 298f494..31ca13a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -115,7 +115,6 @@
HardwareFailed hardware_failed = 72;
PhysicalDropDetected physical_drop_detected = 73;
ChargeCyclesReported charge_cycles_reported = 74;
- // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
// Pulled events will start at field 10000.
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index bfb1ec7..991a76a 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -128,11 +128,11 @@
}
}
- // Stops the anomaly alarm.
- void stopAnomalyAlarm() {
+ // Stops the anomaly alarm. If it should have already fired, declare the anomaly now.
+ void stopAnomalyAlarm(const uint64_t timestamp) {
for (auto& anomalyTracker : mAnomalyTrackers) {
if (anomalyTracker != nullptr) {
- anomalyTracker->stopAlarm(mEventKey);
+ anomalyTracker->stopAlarm(mEventKey, timestamp);
}
}
}
@@ -155,14 +155,6 @@
}
}
- void declareAnomalyIfAlarmExpired(const uint64_t& timestamp) {
- for (auto& anomalyTracker : mAnomalyTrackers) {
- if (anomalyTracker != nullptr) {
- anomalyTracker->declareAnomalyIfAlarmExpired(mEventKey, timestamp);
- }
- }
- }
-
// Convenience to compute the current bucket's end time, which is always aligned with the
// start time of the metric.
uint64_t getCurrentBucketEndTimeNs() {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 058940d..335ec4c 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -130,7 +130,7 @@
case DurationState::kStarted: {
duration.startCount--;
if (forceStop || !mNested || duration.startCount <= 0) {
- stopAnomalyAlarm();
+ stopAnomalyAlarm(eventTime);
duration.state = DurationState::kStopped;
int64_t durationTime = eventTime - duration.lastStartTime;
VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(),
@@ -284,7 +284,7 @@
// If condition becomes false, kStarted -> kPaused. Record the current duration and
// stop anomaly alarm.
if (!conditionMet) {
- stopAnomalyAlarm();
+ stopAnomalyAlarm(timestamp);
it->second.state = DurationState::kPaused;
it->second.lastDuration += (timestamp - it->second.lastStartTime);
if (anyStarted()) {
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index c8a5016..b418a85 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -92,7 +92,6 @@
void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp,
const bool stopAll) {
- declareAnomalyIfAlarmExpired(timestamp);
VLOG("Oring: %s stop", key.toString().c_str());
auto it = mStarted.find(key);
if (it != mStarted.end()) {
@@ -118,12 +117,11 @@
}
}
if (mStarted.empty()) {
- stopAnomalyAlarm();
+ stopAnomalyAlarm(timestamp);
}
}
void OringDurationTracker::noteStopAll(const uint64_t timestamp) {
- declareAnomalyIfAlarmExpired(timestamp);
if (!mStarted.empty()) {
mDuration += (timestamp - mLastStartTime);
VLOG("Oring Stop all: record duration %lld %lld ", (long long)timestamp - mLastStartTime,
@@ -131,7 +129,7 @@
detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
}
- stopAnomalyAlarm();
+ stopAnomalyAlarm(timestamp);
mStarted.clear();
mPaused.clear();
mConditionKeyMap.clear();
@@ -213,7 +211,6 @@
}
void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
- declareAnomalyIfAlarmExpired(timestamp);
vector<pair<HashableDimensionKey, int>> startedToPaused;
vector<pair<HashableDimensionKey, int>> pausedToStarted;
if (!mStarted.empty()) {
@@ -291,12 +288,11 @@
mPaused.insert(startedToPaused.begin(), startedToPaused.end());
if (mStarted.empty()) {
- stopAnomalyAlarm();
+ stopAnomalyAlarm(timestamp);
}
}
void OringDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) {
- declareAnomalyIfAlarmExpired(timestamp);
if (condition) {
if (!mPaused.empty()) {
VLOG("Condition true, all started");
@@ -319,7 +315,7 @@
}
}
if (mStarted.empty()) {
- stopAnomalyAlarm();
+ stopAnomalyAlarm(timestamp);
}
}
@@ -328,12 +324,16 @@
// TODO: Unit-test this and see if it can be done more efficiently (e.g. use int32).
// All variables below represent durations (not timestamps).
+ const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
+
// The time until the current bucket ends. This is how much more 'space' it can hold.
const int64_t currRemainingBucketSizeNs =
mBucketSizeNs - (eventTimestampNs - mCurrentBucketStartTimeNs);
- // TODO: This should never be < 0. Document/guard against possible failures if it is.
-
- const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
+ if (currRemainingBucketSizeNs < 0) {
+ ALOGE("OringDurationTracker currRemainingBucketSizeNs < 0");
+ // This should never happen. Return the safest thing possible given that data is corrupt.
+ return eventTimestampNs + thresholdNs;
+ }
// As we move into the future, old buckets get overwritten (so their old data is erased).
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index b5afef2..901f500 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -562,6 +562,10 @@
(long long)alert.metric_id());
return false;
}
+ if (!alert.has_trigger_if_sum_gt()) {
+ ALOGW("invalid alert: missing threshold");
+ return false;
+ }
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
ALOGW("invalid alert: threshold=%f num_buckets= %d",
alert.trigger_if_sum_gt(), alert.num_buckets());
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index b4a7bb7..218d52a 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -16,6 +16,7 @@
#include "../metrics/metrics_test_helper.h"
#include <gtest/gtest.h>
+#include <math.h>
#include <stdio.h>
#include <vector>
@@ -104,12 +105,12 @@
for (const auto& kv : timestamps) {
if (kv.second < 0) {
// Make sure that, if there is a refractory period, it is already past.
- EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first),
- currTimestampNs / NS_PER_SEC + 1)
+ EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC,
+ (uint64_t)currTimestampNs)
<< "Failure was at currTimestampNs " << currTimestampNs;
} else {
EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
- kv.second / NS_PER_SEC + refractoryPeriodSec)
+ std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec)
<< "Failure was at currTimestampNs " << currTimestampNs;
}
}
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index a07683e..fff1155 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <math.h>
#include <stdio.h>
#include <vector>
@@ -379,13 +380,13 @@
EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
// Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index c0cc0b6..5ef84e6 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -20,6 +20,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <math.h>
#include <stdio.h>
#include <vector>
@@ -392,7 +393,7 @@
.mFields->begin()
->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
std::shared_ptr<LogEvent> event3 =
std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
@@ -407,7 +408,7 @@
.mFields->begin()
->mValue.int_value);
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
// The event4 does not have the gauge field. Thus the current bucket value is 0.
std::shared_ptr<LogEvent> event4 =
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 54abcb2..9b27f3c 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <math.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
@@ -416,7 +417,7 @@
tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
- (eventStartTimeNs + 2 * bucketSizeNs + 25) / NS_PER_SEC + refPeriodSec);
+ std::ceil((eventStartTimeNs + 2 * bucketSizeNs + 25.0) / NS_PER_SEC + refPeriodSec));
}
TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index a0addcc..a8eb2703 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -19,6 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <math.h>
#include <stdio.h>
#include <vector>
@@ -415,16 +416,16 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
// Anomaly at event 4 since Value sum == 131 > 130!
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
// Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
// Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
- event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec);
+ std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
}
} // namespace statsd
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 99d871e..b1f1f1c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -117,8 +117,8 @@
Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;I)Z
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
-Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V
+Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -148,6 +148,7 @@
Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
Landroid/app/ApplicationPackageManager;->configurationChanged()V
Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
+Landroid/app/ApplicationPackageManager;->getPackageCurrentVolume(Landroid/content/pm/ApplicationInfo;)Landroid/os/storage/VolumeInfo;
Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
Landroid/app/ApplicationPackageManager;->mPM:Landroid/content/pm/IPackageManager;
@@ -175,6 +176,7 @@
Landroid/app/backup/BackupHelperDispatcher$Header;->keyPrefix:Ljava/lang/String;
Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I
Landroid/app/backup/FullBackupDataOutput;->addSize(J)V
+Landroid/app/backup/FullBackupDataOutput;-><init>(Landroid/os/ParcelFileDescriptor;)V
Landroid/app/backup/FullBackupDataOutput;->mData:Landroid/app/backup/BackupDataOutput;
Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
@@ -281,6 +283,7 @@
Landroid/app/Notification;->mLargeIcon:Landroid/graphics/drawable/Icon;
Landroid/app/Notification;->mSmallIcon:Landroid/graphics/drawable/Icon;
Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
+Landroid/app/Notification;->setSmallIcon(Landroid/graphics/drawable/Icon;)V
Landroid/app/PendingIntent;->getActivityAsUser(Landroid/content/Context;ILandroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/PendingIntent;
Landroid/app/PendingIntent;->getIntent()Landroid/content/Intent;
Landroid/app/PendingIntent;->isActivity()Z
@@ -327,7 +330,9 @@
Landroid/appwidget/AppWidgetManager;->mService:Lcom/android/internal/appwidget/IAppWidgetService;
Landroid/bluetooth/BluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
+Landroid/bluetooth/BluetoothAdapter;->factoryReset()Z
Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I
+Landroid/bluetooth/BluetoothAdapter;->getLeState()I
Landroid/bluetooth/BluetoothAdapter;->mService:Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z
Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z
@@ -337,8 +342,11 @@
Landroid/bluetooth/BluetoothGattCharacteristic;->mService:Landroid/bluetooth/BluetoothGattService;
Landroid/bluetooth/BluetoothGattDescriptor;->mCharacteristic:Landroid/bluetooth/BluetoothGattCharacteristic;
Landroid/bluetooth/BluetoothGattDescriptor;->mInstance:I
+Landroid/bluetooth/BluetoothGatt;->mAuthRetryState:I
Landroid/bluetooth/BluetoothGatt;->refresh()Z
Landroid/bluetooth/BluetoothHeadset;->close()V
+Landroid/bluetooth/BluetoothPan;->isTetheringOn()Z
+Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V
Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -610,6 +618,12 @@
Landroid/graphics/drawable/GradientDrawable$GradientState;->mThicknessRatio:F
Landroid/graphics/drawable/GradientDrawable$GradientState;->mWidth:I
Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect;
+Landroid/graphics/drawable/Icon;->getBitmap()Landroid/graphics/Bitmap;
+Landroid/graphics/drawable/Icon;->getDataBytes()[B
+Landroid/graphics/drawable/Icon;->getDataLength()I
+Landroid/graphics/drawable/Icon;->getDataOffset()I
+Landroid/graphics/drawable/Icon;->getResources()Landroid/content/res/Resources;
+Landroid/graphics/drawable/Icon;->hasTint()Z
Landroid/graphics/drawable/Icon;->mType:I
Landroid/graphics/drawable/InsetDrawable;->mState:Landroid/graphics/drawable/InsetDrawable$InsetState;
Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;
@@ -817,6 +831,7 @@
Landroid/media/AudioManager;->getService()Landroid/media/IAudioService;
Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
Landroid/media/AudioManager;->setMasterMute(ZI)V
+Landroid/media/AudioManager;->startBluetoothScoVirtualCall()V
Landroid/media/AudioManager;->STREAM_BLUETOOTH_SCO:I
Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I
Landroid/media/AudioManager;->STREAM_TTS:I
@@ -860,6 +875,7 @@
Landroid/media/AudioSystem;->errorCallbackFromNative(I)V
Landroid/media/AudioSystem;->getPrimaryOutputFrameCount()I
Landroid/media/AudioSystem;->getPrimaryOutputSamplingRate()I
+Landroid/media/AudioSystem;->isStreamActive(II)Z
Landroid/media/AudioSystem;->recordingCallbackFromNative(IIII[I)V
Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
Landroid/media/AudioSystem;->setErrorCallback(Landroid/media/AudioSystem$ErrorCallback;)V
@@ -1045,6 +1061,22 @@
Landroid/net/wifi/ScanResult;->distanceSdCm:I
Landroid/net/wifi/ScanResult;->flags:J
Landroid/net/wifi/ScanResult;->hessid:J
+Landroid/net/wifi/ScanResult$InformationElement;->bytes:[B
+Landroid/net/wifi/ScanResult$InformationElement;->EID_BSS_LOAD:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_ERP:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_CAPS:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_EXTENDED_SUPPORTED_RATES:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_HT_OPERATION:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_INTERWORKING:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_ROAMING_CONSORTIUM:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_RSN:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_SSID:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_SUPPORTED_RATES:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_TIM:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_VHT_OPERATION:I
+Landroid/net/wifi/ScanResult$InformationElement;->EID_VSA:I
+Landroid/net/wifi/ScanResult$InformationElement;->id:I
+Landroid/net/wifi/ScanResult;->informationElements:[Landroid/net/wifi/ScanResult$InformationElement;
Landroid/net/wifi/ScanResult;->numUsage:I
Landroid/net/wifi/ScanResult;->seen:J
Landroid/net/wifi/ScanResult;->untrusted:Z
@@ -1182,6 +1214,7 @@
Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
Landroid/os/Parcel$ReadWriteHelper;-><init>()V
Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
+Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
@@ -1371,6 +1404,8 @@
Landroid/provider/Settings$Global;->ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Global;->PACKAGE_VERIFIER_ENABLE:Ljava/lang/String;
Landroid/provider/Settings$Global;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
+Landroid/provider/Settings;->isCallingPackageAllowedToDrawOverlays(Landroid/content/Context;ILjava/lang/String;Z)Z
+Landroid/provider/Settings;->isCallingPackageAllowedToWriteSettings(Landroid/content/Context;ILjava/lang/String;Z)Z
Landroid/provider/Settings$NameValueCache;->mProviderHolder:Landroid/provider/Settings$ContentProviderHolder;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_AUTOCLICK_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$Secure;->ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:Ljava/lang/String;
@@ -1385,6 +1420,7 @@
Landroid/provider/Settings$System;->HEARING_AID:Ljava/lang/String;
Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
Landroid/provider/Settings$System;->putStringForUser(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;I)Z
+Landroid/provider/Settings$System;->SCREEN_AUTO_BRIGHTNESS_ADJ:Ljava/lang/String;
Landroid/provider/Settings$System;->sNameValueCache:Landroid/provider/Settings$NameValueCache;
Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZJ)Landroid/net/Uri;
Landroid/provider/Telephony$Sms;->addMessageToUri(ILandroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZZ)Landroid/net/Uri;
@@ -2036,6 +2072,7 @@
Landroid/view/View;->dispatchDetachedFromWindow()V
Landroid/view/View;->fitsSystemWindows()Z
Landroid/view/View;->getAccessibilityDelegate()Landroid/view/View$AccessibilityDelegate;
+Landroid/view/View;->getInverseMatrix()Landroid/graphics/Matrix;
Landroid/view/View;->getListenerInfo()Landroid/view/View$ListenerInfo;
Landroid/view/View;->getLocationOnScreen()[I
Landroid/view/View;->getTransitionAlpha()F
@@ -2207,6 +2244,7 @@
Landroid/widget/EdgeEffect;->mPaint:Landroid/graphics/Paint;
Landroid/widget/Editor;->invalidateTextDisplayList()V
Landroid/widget/Editor;->mShowCursor:J
+Landroid/widget/Editor;->mShowSoftInputOnFocus:Z
Landroid/widget/ExpandableListView;->mChildDivider:Landroid/graphics/drawable/Drawable;
Landroid/widget/FastScroller;->mContainerRect:Landroid/graphics/Rect;
Landroid/widget/FastScroller;->mHeaderCount:I
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index cab6744..2752fa9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -69,6 +69,13 @@
AppProtoEnums.APP_TRANSITION_SNAPSHOT; // 4
/**
+ * Type for {@link #notifyAppTransitionStarting}: The transition was started because it was a
+ * recents animation and we only needed to wait on the wallpaper.
+ */
+ public static final int APP_TRANSITION_RECENTS_ANIM =
+ AppProtoEnums.APP_TRANSITION_RECENTS_ANIM; // 5
+
+ /**
* The bundle key to extract the assist data.
*/
public static final String ASSIST_KEY_DATA = "data";
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index b12e3bc..7325daa7 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -103,12 +103,12 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when adding configuration");
+ Slog.e(TAG, "Failed to find statsd when adding configuration");
return false;
}
return service.addConfiguration(configKey, config);
} catch (RemoteException e) {
- if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when adding configuration");
+ Slog.e(TAG, "Failed to connect to statsd when adding configuration");
return false;
}
}
@@ -126,12 +126,12 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when removing configuration");
+ Slog.e(TAG, "Failed to find statsd when removing configuration");
return false;
}
return service.removeConfiguration(configKey);
} catch (RemoteException e) {
- if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when removing configuration");
+ Slog.e(TAG, "Failed to connect to statsd when removing configuration");
return false;
}
}
@@ -173,7 +173,7 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- Slog.w(TAG, "Failed to find statsd when adding broadcast subscriber");
+ Slog.e(TAG, "Failed to find statsd when adding broadcast subscriber");
return false;
}
if (pendingIntent != null) {
@@ -184,7 +184,7 @@
return service.unsetBroadcastSubscriber(configKey, subscriberId);
}
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
+ Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
return false;
}
}
@@ -210,7 +210,7 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- Slog.d(TAG, "Failed to find statsd when registering data listener.");
+ Slog.e(TAG, "Failed to find statsd when registering data listener.");
return false;
}
if (pendingIntent == null) {
@@ -222,7 +222,7 @@
}
} catch (RemoteException e) {
- Slog.d(TAG, "Failed to connect to statsd when registering data listener.");
+ Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
return false;
}
}
@@ -241,12 +241,12 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting data");
+ Slog.e(TAG, "Failed to find statsd when getting data");
return null;
}
return service.getData(configKey);
} catch (RemoteException e) {
- if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data");
+ Slog.e(TAG, "Failed to connect to statsd when getting data");
return null;
}
}
@@ -265,12 +265,12 @@
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting metadata");
+ Slog.e(TAG, "Failed to find statsd when getting metadata");
return null;
}
return service.getMetadata();
} catch (RemoteException e) {
- if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting metadata");
+ Slog.e(TAG, "Failed to connect to statsd when getting metadata");
return null;
}
}
diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java
index 4f86af9..f67d7f5 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -79,7 +79,17 @@
/**
* Used to indicate to the SyncManager that future sync requests that match the request's
- * Account and authority should be delayed at least this many seconds.
+ * Account and authority should be delayed until a time in seconds since Java epoch.
+ *
+ * <p>For example, if you want to delay the next sync for at least 5 minutes, then:
+ * <pre>
+ * result.delayUntil = (System.currentTimeMillis() / 1000) + 5 * 60;
+ * </pre>
+ *
+ * <p>By default, when a sync fails, the system retries later with an exponential back-off
+ * with the system default initial delay time, which always wins over {@link #delayUntil} --
+ * i.e. if the system back-off time is larger than {@link #delayUntil}, {@link #delayUntil}
+ * will essentially be ignored.
*/
public long delayUntil;
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java
index f6127e1..1697106 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationDialog.java
@@ -227,12 +227,32 @@
return uiOptionsAsFlags;
}
+ private boolean isAccessibilityServiceRunning() {
+ boolean serviceRunning = false;
+ try {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int a11yEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_ENABLED);
+ if (a11yEnabled == 1) {
+ serviceRunning = true;
+ }
+ } catch (SettingNotFoundException e) {
+ Log.w(TAG, "Unexpected SettingNotFoundException");
+ e.printStackTrace();
+ }
+ return serviceRunning;
+ }
+
/**
* Requests a confirmation prompt to be presented to the user.
*
* When the prompt is no longer being presented, one of the methods in
* {@link ConfirmationCallback} is called on the supplied callback object.
*
+ * Confirmation dialogs may not be available when accessibility services are running so this
+ * may fail with a {@link ConfirmationNotAvailableException} exception even if
+ * {@link #isSupported} returns {@code true}.
+ *
* @param executor the executor identifying the thread that will receive the callback.
* @param callback the callback to use when the dialog is done showing.
* @throws IllegalArgumentException if the prompt text is too long or malfomed.
@@ -245,6 +265,9 @@
if (mCallback != null) {
throw new ConfirmationAlreadyPresentingException();
}
+ if (isAccessibilityServiceRunning()) {
+ throw new ConfirmationNotAvailableException();
+ }
mCallback = callback;
mExecutor = executor;
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
index 5eb05be..1754e42 100644
--- a/core/proto/android/app/enums.proto
+++ b/core/proto/android/app/enums.proto
@@ -32,6 +32,9 @@
APP_TRANSITION_TIMEOUT = 3;
// The transition was started because of a we drew a task snapshot.
APP_TRANSITION_SNAPSHOT = 4;
+ // The transition was started because it was a recents animation and we only needed to wait on
+ // the wallpaper.
+ APP_TRANSITION_RECENTS_ANIM = 5;
}
// ActivityManager.java PROCESS_STATEs
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index f18e347..48b7a51 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -129,6 +129,33 @@
*/
public abstract void seekTo(long pos);
+ /**
+ * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
+ * <p>
+ * Default implementation sets the playback speed to the 2.0f
+ * @see #setPlaybackSpeed(float)
+ * @hide
+ */
+ // TODO(jaewan): Unhide (b/74724709)
+ public void fastForward() {
+ setPlaybackSpeed(2.0f);
+ }
+
+ /**
+ * Rewinds playback. If playback is already rewinding this may increase the rate.
+ * <p>
+ * Default implementation sets the playback speed to the -1.0f if
+ * {@link #isReversePlaybackSupported()} returns {@code true}.
+ * @see #setPlaybackSpeed(float)
+ * @hide
+ */
+ // TODO(jaewan): Unhide (b/74724709)
+ public void rewind() {
+ if (isReversePlaybackSupported()) {
+ setPlaybackSpeed(-1.0f);
+ }
+ }
+
public static final long UNKNOWN_TIME = -1;
/**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 60714df..6647831 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -1418,14 +1418,14 @@
}
/**
- * Start fast forwarding. If playback is already fast forwarding this may increase the rate.
+ * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
*/
public void fastForward() {
mProvider.fastForward_impl();
}
/**
- * Start rewinding. If playback is already rewinding this may increase the rate.
+ * Rewinds playback. If playback is already rewinding this may increase the rate.
*/
public void rewind() {
mProvider.rewind_impl();
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index 0d190a7..cf18bdd 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -16,49 +16,73 @@
package android.media.update;
-import android.annotation.NonNull;
-import android.content.res.Resources;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
/**
* @hide
*/
public final class ApiLoader {
- private static Object sMediaLibrary;
+ @GuardedBy("this")
+ private static StaticProvider sMediaUpdatable;
private static final String UPDATE_PACKAGE = "com.android.media.update";
private static final String UPDATE_CLASS = "com.android.media.update.ApiFactory";
private static final String UPDATE_METHOD = "initialize";
+ private static final boolean REGISTER_UPDATE_DEPENDENCY = true;
private ApiLoader() { }
- public static StaticProvider getProvider(@NonNull Context context) {
- if (context == null) {
- throw new IllegalArgumentException("context shouldn't be null");
- }
+ @Deprecated
+ public static StaticProvider getProvider(Context context) {
+ return getProvider();
+ }
+
+ public static StaticProvider getProvider() {
+ if (sMediaUpdatable != null) return sMediaUpdatable;
+
try {
- return (StaticProvider) getMediaLibraryImpl(context);
- } catch (PackageManager.NameNotFoundException | ReflectiveOperationException e) {
+ return getMediaUpdatable();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (NameNotFoundException | ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
// TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
- private static synchronized Object getMediaLibraryImpl(Context context)
- throws PackageManager.NameNotFoundException, ReflectiveOperationException {
- if (sMediaLibrary != null) return sMediaLibrary;
+ private static synchronized StaticProvider getMediaUpdatable()
+ throws NameNotFoundException, ReflectiveOperationException, RemoteException {
+ if (sMediaUpdatable != null) return sMediaUpdatable;
// TODO Figure out when to use which package (query media update service)
int flags = Build.IS_DEBUGGABLE ? 0 : PackageManager.MATCH_FACTORY_ONLY;
- Context libContext = context.createApplicationContext(
- context.getPackageManager().getPackageInfo(UPDATE_PACKAGE, flags).applicationInfo,
- Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
- sMediaLibrary = libContext.getClassLoader()
- .loadClass(UPDATE_CLASS)
- .getMethod(UPDATE_METHOD, Resources.class, Resources.Theme.class)
- .invoke(null, libContext.getResources(), libContext.getTheme());
- return sMediaLibrary;
+ flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ UPDATE_PACKAGE, flags, UserHandle.myUserId());
+
+ if (REGISTER_UPDATE_DEPENDENCY) {
+ // Register a dependency to the updatable in order to be killed during updates
+ ActivityManager.getService().addPackageDependency(ai.packageName);
+ }
+
+ PathClassLoader classLoader = new PathClassLoader(ai.sourceDir,
+ ai.nativeLibraryDir + File.pathSeparator + System.getProperty("java.library.path"),
+ ClassLoader.getSystemClassLoader().getParent());
+ return sMediaUpdatable = (StaticProvider) classLoader.loadClass(UPDATE_CLASS)
+ .getMethod(UPDATE_METHOD, ApplicationInfo.class).invoke(null, ai);
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e77db82..fe785c2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -887,13 +887,13 @@
<string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
<!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery -->
- <string name="power_discharge_by_enhanced">Will last until about <xliff:g id="time">%1$s</xliff:g> based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <string name="power_discharge_by_enhanced">Should last until about <xliff:g id="time">%1$s</xliff:g> based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
<!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery with no percentage -->
- <string name="power_discharge_by_only_enhanced">Will last until about <xliff:g id="time">%1$s</xliff:g> based on your usage</string>
+ <string name="power_discharge_by_only_enhanced">Should last until about <xliff:g id="time">%1$s</xliff:g> based on your usage</string>
<!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
- <string name="power_discharge_by">Will last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
+ <string name="power_discharge_by">Should last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
<!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
- <string name="power_discharge_by_only">Will last until about <xliff:g id="time">%1$s</xliff:g></string>
+ <string name="power_discharge_by_only">Should last until about <xliff:g id="time">%1$s</xliff:g></string>
<!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
<string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
index 5758467..c11687b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -40,7 +40,7 @@
public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
public static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis();
public static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis();
- public static final String NORMAL_CASE_EXPECTED_PREFIX = "Will last until about";
+ public static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about";
public static final String ENHANCED_SUFFIX = " based on your usage";
// matches a time (ex: '1:15 PM', '2 AM')
public static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* (AM)|(PM)";
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
index eba1d0f..4ee3bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -16,6 +16,7 @@
package com.android.systemui;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.util.Assert;
import android.os.Handler;
@@ -30,9 +31,13 @@
private static final Choreographer sChoreographer = Choreographer.getInstance();
private static final Handler sHandler = new Handler();
-
private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>();
+ /**
+ * Only for testing.
+ */
+ private static boolean sImmediate;
+
private static final Runnable sAnimationCallbackRunnable = new Runnable() {
@Override
public void run() {
@@ -51,6 +56,10 @@
* <p>Needs to be called from the main thread.
*/
public static void postAfterTraversal(Runnable r) {
+ if (sImmediate) {
+ r.run();
+ return;
+ }
Assert.isMainThread();
sPendingRunnables.add(r);
postAnimationCallback();
@@ -71,4 +80,9 @@
sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, sAnimationCallbackRunnable,
null);
}
+
+ @VisibleForTesting
+ public static void setImmediate(boolean immediate) {
+ sImmediate = immediate;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d1834e9..91edfda 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,6 +27,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency.DependencyProvider;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -95,7 +96,7 @@
LockPatternUtils lockPatternUtils,
ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry) {
return new KeyguardBouncer(context, callback, lockPatternUtils, container,
- dismissCallbackRegistry);
+ dismissCallbackRegistry, FalsingManager.getInstance(context));
}
public ScrimController createScrimController(LightBarController lightBarController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 475a609..1807465 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -107,11 +107,6 @@
}
@Override
- public void setBackground(Drawable background) {
- Log.wtfStack(TAG, "ScrimView should never have a background.");
- }
-
- @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int densityDpi = newConfig.densityDpi;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 1d9cdf7..3bbfe3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -77,6 +77,9 @@
public RemoteAnimationAdapter getLaunchAnimation(
ExpandableNotificationRow sourceNotification) {
+ if (mStatusBar.getBarState() != StatusBarState.SHADE) {
+ return null;
+ }
AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
0 /* statusBarTransitionDelay */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 010b165..2a1813f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.phone;
+import static com.android.keyguard.KeyguardHostView.OnDismissAction;
+import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+
import android.content.Context;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.util.StatsLog;
@@ -29,7 +33,6 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardHostView;
@@ -42,9 +45,6 @@
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
-import static com.android.keyguard.KeyguardHostView.OnDismissAction;
-import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-
/**
* A class which manages the bouncer on the lockscreen.
*/
@@ -76,13 +76,13 @@
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
- DismissCallbackRegistry dismissCallbackRegistry) {
+ DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
- mFalsingManager = FalsingManager.getInstance(mContext);
+ mFalsingManager = falsingManager;
mDismissCallbackRegistry = dismissCallbackRegistry;
mHandler = new Handler();
}
@@ -91,7 +91,14 @@
show(resetSecuritySelection, true /* notifyFalsing */);
}
- public void show(boolean resetSecuritySelection, boolean notifyFalsing) {
+ /**
+ * Shows the bouncer.
+ *
+ * @param resetSecuritySelection Cleans keyguard view
+ * @param animated true when the bouncer show show animated, false when the user will be
+ * dragging it and animation should be deferred.
+ */
+ public void show(boolean resetSecuritySelection, boolean animated) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
@@ -104,9 +111,11 @@
// are valid.
// Later, at the end of the animation, when the bouncer is at the top of the screen,
// onFullyShown() will be called and FalsingManager will stop recording touches.
- if (notifyFalsing) {
+ if (animated) {
mFalsingManager.onBouncerShown();
+ setExpansion(0);
}
+
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
@@ -157,7 +166,9 @@
public void onFullyHidden() {
if (!mShowingSoon) {
cancelShowRunnable();
- mRoot.setVisibility(View.INVISIBLE);
+ if (mRoot != null) {
+ mRoot.setVisibility(View.INVISIBLE);
+ }
mFalsingManager.onBouncerHidden();
}
}
@@ -202,11 +213,19 @@
* and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
*/
public void showPromptReason(int reason) {
- mKeyguardView.showPromptReason(reason);
+ if (mKeyguardView != null) {
+ mKeyguardView.showPromptReason(reason);
+ } else {
+ Log.w(TAG, "Trying to show prompt reason on empty bouncer");
+ }
}
public void showMessage(String message, int color) {
- mKeyguardView.showMessage(message, color);
+ if (mKeyguardView != null) {
+ mKeyguardView.showMessage(message, color);
+ } else {
+ Log.w(TAG, "Trying to show message on empty bouncer");
+ }
}
private void cancelShowRunnable() {
@@ -290,7 +309,8 @@
*/
public void setExpansion(float fraction) {
if (mKeyguardView != null) {
- mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction));
+ float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
+ mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7f1e9d0..04cb620 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -947,6 +947,17 @@
return mClosing || mLaunchingNotification;
}
+ /**
+ * Bouncer might need a scrim when you double tap on notifications or edit QS.
+ * On other cases, when you drag up the bouncer with the finger or just fling,
+ * the scrim should be hidden to avoid occluding the clock.
+ *
+ * @return true when we need a scrim to show content on top of the notification panel.
+ */
+ public boolean needsScrimming() {
+ return !isTracking() && !isCollapsing() && !isFullyCollapsed();
+ }
+
public boolean isTracking() {
return mTracking;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f8b4e07..ae55ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -239,6 +239,11 @@
mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
applyExpansionToAlpha();
+ // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
+ // We need to disable focus otherwise AOD would end up with a gray overlay.
+ mScrimInFront.setFocusable(!state.isLowPowerState());
+ mScrimBehind.setFocusable(!state.isLowPowerState());
+
// Cancel blanking transitions that were pending before we requested a new state
if (mPendingFrameCallback != null) {
Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
@@ -257,7 +262,7 @@
// the animation plays properly until the last frame.
// It's important to avoid holding the wakelock unless necessary because
// WakeLock#aqcuire will trigger an IPC and will cause jank.
- if (mState == ScrimState.AOD) {
+ if (mState.isLowPowerState()) {
holdWakeLock();
}
@@ -449,7 +454,7 @@
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
final GradientColors currentScrimColors;
- if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED
+ if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED
|| mState == ScrimState.BOUNCER) {
// Always animate color changes if we're seeing the keyguard
mScrimInFront.setColors(mLockColors, true /* animated */);
@@ -528,7 +533,7 @@
scrim.setClickable(false);
} else {
// Eat touch events (unless dozing).
- scrim.setClickable(!(mState == ScrimState.AOD));
+ scrim.setClickable(!mState.isLowPowerState());
}
updateScrim(scrim, alpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 58100ef..55e8714 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -79,7 +79,7 @@
/**
* Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity.
*/
- BOUNCER_OCCLUDED(2) {
+ BOUNCER_SCRIMMED(2) {
@Override
public void prepare(ScrimState previousState) {
mCurrentBehindAlpha = 0;
@@ -116,6 +116,11 @@
// to set our state.
mAnimateChange = mCanControlScreenOff;
}
+
+ @Override
+ public boolean isLowPowerState() {
+ return true;
+ }
},
/**
@@ -250,4 +255,8 @@
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
}
+
+ public boolean isLowPowerState() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2e45b12..5bc45cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3907,12 +3907,12 @@
private void showBouncerIfKeyguard() {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- showBouncer();
+ showBouncer(true /* animated */);
}
}
- protected void showBouncer() {
- mStatusBarKeyguardViewManager.dismiss();
+ protected void showBouncer(boolean animated) {
+ mStatusBarKeyguardViewManager.showBouncer(animated);
}
private void instantExpandNotificationsPanel() {
@@ -4026,7 +4026,7 @@
public void onTrackingStopped(boolean expand) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
- showBouncerIfKeyguard();
+ showBouncer(false /* animated */);
}
}
}
@@ -4165,7 +4165,7 @@
@Override
public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
mLeaveOpenOnKeyguardHide = true;
- showBouncer();
+ showBouncer(true /* animated */);
mPendingRemoteInputView = clicked;
}
@@ -4631,9 +4631,10 @@
!= FingerprintUnlockController.MODE_UNLOCK);
if (mBouncerShowing) {
- final boolean qsExpanded = mQSPanel != null && mQSPanel.isExpanded();
- mScrimController.transitionTo(mIsOccluded || qsExpanded ?
- ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER);
+ // Bouncer needs the front scrim when it's on top of an activity,
+ // tapping on a notification or editing QS.
+ mScrimController.transitionTo(mIsOccluded || mNotificationPanel.needsScrimming() ?
+ ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER);
} else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {
@@ -5043,8 +5044,11 @@
RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
row);
try {
- ActivityManager.getService().registerRemoteAnimationForNextActivityStart(
- intent.getCreatorPackage(), adapter);
+ if (adapter != null) {
+ ActivityManager.getService()
+ .registerRemoteAnimationForNextActivityStart(
+ intent.getCreatorPackage(), adapter);
+ }
launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
null, null, getActivityOptions(adapter));
mActivityLaunchAnimator.setLaunchResult(launchResult);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 8d536d8..b26b7c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -198,9 +198,9 @@
cancelPendingWakeupAction();
}
- private void showBouncer() {
+ public void showBouncer(boolean animated) {
if (mShowing) {
- mBouncer.show(false /* resetSecuritySelection */);
+ mBouncer.show(false /* resetSecuritySelection */, animated);
}
updateStates();
}
@@ -485,10 +485,6 @@
mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true);
}
- public void dismiss() {
- showBouncer();
- }
-
/**
* WARNING: This method might cause Binder calls.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 4051220..f3a8417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -16,39 +16,268 @@
package com.android.systemui.statusbar.phone;
-import static org.mockito.Mockito.mock;
+import static com.google.common.truth.Truth.assertThat;
-import android.content.Context;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.calls;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Color;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.UiThreadTest;
-import android.view.ContextThemeWrapper;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.R;
+import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class KeyguardBouncerTest extends SysuiTestCase {
- @UiThreadTest
- @Test
- public void inflateDetached() {
- final ViewGroup container = new FrameLayout(getContext());
- final KeyguardBouncer bouncer = new KeyguardBouncer(getContext(),
- mock(ViewMediatorCallback.class), mock(LockPatternUtils.class), container, mock(
- DismissCallbackRegistry.class));
+ @Mock
+ private FalsingManager mFalsingManager;
+ @Mock
+ private ViewMediatorCallback mViewMediatorCallback;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private DismissCallbackRegistry mDismissCallbackRegistry;
+ @Mock
+ private KeyguardHostView mKeyguardHostView;
+ @Mock
+ private ViewTreeObserver mViewTreeObserver;
- // Detached bouncer should still be able to be inflated
- bouncer.inflateView();
+ private KeyguardBouncer mBouncer;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ DejankUtils.setImmediate(true);
+ final ViewGroup container = new FrameLayout(getContext());
+ when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+ when(mKeyguardHostView.getHeight()).thenReturn(500);
+ mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback,
+ mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager) {
+ @Override
+ protected void inflateView() {
+ super.inflateView();
+ mKeyguardView = mKeyguardHostView;
+ }
+ };
}
+ @Test
+ public void testInflateView_doesntCrash() {
+ mBouncer.inflateView();
+ }
+
+ @Test
+ public void testShow_notifiesFalsingManager() {
+ mBouncer.show(true);
+ verify(mFalsingManager).onBouncerShown();
+
+ mBouncer.show(true, false);
+ verifyNoMoreInteractions(mFalsingManager);
+ }
+
+ /**
+ * Regression test: Invisible bouncer when occluded.
+ */
+ @Test
+ public void testShow_bouncerIsVisible() {
+ // Expand notification panel as if we were in the keyguard.
+ mBouncer.ensureView();
+ mBouncer.setExpansion(1);
+
+ reset(mKeyguardHostView);
+ when(mKeyguardHostView.getHeight()).thenReturn(500);
+
+ mBouncer.show(true);
+ verify(mKeyguardHostView).setAlpha(eq(1f));
+ verify(mKeyguardHostView).setTranslationY(eq(0f));
+ }
+
+ @Test
+ public void testShow_notifiesVisibility() {
+ mBouncer.show(true);
+ verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(true));
+
+ // Not called again when visible
+ reset(mViewMediatorCallback);
+ mBouncer.show(true);
+ verifyNoMoreInteractions(mViewMediatorCallback);
+ }
+
+ @Test
+ public void testShow_triesToDismissKeyguard() {
+ mBouncer.show(true);
+ verify(mKeyguardHostView).dismiss(anyInt());
+ }
+
+ @Test
+ public void testShow_resetsSecuritySelection() {
+ mBouncer.show(false);
+ verify(mKeyguardHostView, never()).showPrimarySecurityScreen();
+
+ mBouncer.hide(false);
+ mBouncer.show(true);
+ verify(mKeyguardHostView).showPrimarySecurityScreen();
+ }
+
+ @Test
+ public void testShow_animatesKeyguardView() {
+ mBouncer.show(true);
+ verify(mKeyguardHostView).startAppearAnimation();
+ }
+
+ @Test
+ public void testShow_showsErrorMessage() {
+ final String errorMessage = "an error message";
+ when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage);
+ mBouncer.show(true);
+ verify(mKeyguardHostView).showErrorMessage(eq(errorMessage));
+ }
+
+ @Test
+ public void testOnFullyShown_notifiesFalsingManager() {
+ mBouncer.onFullyShown();
+ verify(mFalsingManager).onBouncerShown();
+ }
+
+ @Test
+ public void testOnFullyHidden_notifiesFalsingManager() {
+ mBouncer.onFullyHidden();
+ verify(mFalsingManager).onBouncerHidden();
+ }
+
+ @Test
+ public void testHide_notifiesFalsingManager() {
+ mBouncer.hide(false);
+ verify(mFalsingManager).onBouncerHidden();
+ }
+
+ @Test
+ public void testHide_notifiesVisibility() {
+ mBouncer.hide(false);
+ verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(false));
+ }
+
+ @Test
+ public void testHide_notifiesDismissCallbackIfVisible() {
+ mBouncer.hide(false);
+ verifyZeroInteractions(mDismissCallbackRegistry);
+ mBouncer.show(false);
+ mBouncer.hide(false);
+ verify(mDismissCallbackRegistry).notifyDismissCancelled();
+ }
+
+ @Test
+ public void testShowPromptReason_propagates() {
+ mBouncer.ensureView();
+ mBouncer.showPromptReason(1);
+ verify(mKeyguardHostView).showPromptReason(eq(1));
+ }
+
+ @Test
+ public void testShowMessage_propagates() {
+ final String message = "a message";
+ mBouncer.ensureView();
+ mBouncer.showMessage(message, Color.GREEN);
+ verify(mKeyguardHostView).showMessage(eq(message), eq(Color.GREEN));
+ }
+
+ @Test
+ public void testShowOnDismissAction_showsBouncer() {
+ final KeyguardHostView.OnDismissAction dismissAction = () -> false;
+ final Runnable cancelAction = () -> {};
+ mBouncer.showWithDismissAction(dismissAction, cancelAction);
+ verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction);
+ Assert.assertTrue("Should be showing", mBouncer.isShowing());
+ }
+
+ @Test
+ public void testStartPreHideAnimation_notifiesView() {
+ final boolean[] ran = {false};
+ final Runnable r = () -> ran[0] = true;
+ mBouncer.startPreHideAnimation(r);
+ Assert.assertTrue("Callback should have been invoked", ran[0]);
+
+ ran[0] = false;
+ mBouncer.ensureView();
+ mBouncer.startPreHideAnimation(r);
+ verify(mKeyguardHostView).startDisappearAnimation(r);
+ Assert.assertFalse("Callback should have been deferred", ran[0]);
+ }
+
+ @Test
+ public void testIsShowing() {
+ Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing());
+ mBouncer.show(true);
+ Assert.assertTrue("Should be showing", mBouncer.isShowing());
+ }
+
+ @Test
+ public void testSetExpansion() {
+ mBouncer.ensureView();
+ mBouncer.setExpansion(0.5f);
+ verify(mKeyguardHostView).setAlpha(anyFloat());
+ verify(mKeyguardHostView).setTranslationY(anyFloat());
+ }
+
+ @Test
+ public void testNeedsFullscreenBouncer_asksKeyguardView() {
+ mBouncer.ensureView();
+ mBouncer.needsFullscreenBouncer();
+ verify(mKeyguardHostView).getSecurityMode();
+ verify(mKeyguardHostView, never()).getCurrentSecurityMode();
+ }
+
+ @Test
+ public void testIsFullscreenBouncer_asksKeyguardView() {
+ mBouncer.ensureView();
+ mBouncer.isFullscreenBouncer();
+ verify(mKeyguardHostView).getCurrentSecurityMode();
+ verify(mKeyguardHostView, never()).getSecurityMode();
+ }
+
+ @Test
+ public void testIsSecure() {
+ Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure());
+
+ mBouncer.ensureView();
+ for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){
+ reset(mKeyguardHostView);
+ when(mKeyguardHostView.getSecurityMode()).thenReturn(mode);
+ Assert.assertEquals("Security doesn't match for mode: " + mode,
+ mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 6fbc0d7..f088c0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -42,6 +42,7 @@
import android.view.Choreographer;
import android.view.View;
+import com.android.internal.util.Preconditions;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.ScrimView;
@@ -181,7 +182,7 @@
@Test
public void transitionToBouncer() {
- mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED);
+ mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);
mScrimController.finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be visible without tint
@@ -463,6 +464,17 @@
mHeadsUpScrim.getAlpha(), 0.01f);
}
+ @Test
+ public void testScrimFocus() {
+ mScrimController.transitionTo(ScrimState.AOD);
+ Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable());
+ Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable());
+
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable());
+ Assert.assertTrue("Should be focusable on keyguard", mScrimInFront.isFocusable());
+ }
+
/**
* Conserves old notification density after leaving state and coming back.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
index 56de32d..11bb398 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
@@ -24,6 +24,7 @@
import com.android.systemui.util.leak.ReferenceTestUtils.CollectionWaiter;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -82,6 +83,7 @@
collectionWaiter.waitForCollection();
}
+ @Ignore("b/75329085")
@Test
public void trackCollection_doesNotLeakTrackedObject() {
CollectionWaiter collectionWaiter = trackCollectionWith(mLeakDetector::trackCollection);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 04d46aa..063c1f1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -110,6 +110,7 @@
import static android.os.Process.setThreadScheduler;
import static android.os.Process.startWebView;
import static android.os.Process.zygoteProcess;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -737,6 +738,13 @@
private ActivityRecord mLastResumedActivity;
/**
+ * The activity that is currently being traced as the active resumed activity.
+ *
+ * @see #updateResumedAppTrace
+ */
+ private @Nullable ActivityRecord mTracedResumedActivity;
+
+ /**
* If non-null, we are tracking the time the user spends in the currently focused app.
*/
private AppTimeTracker mCurAppTimeTracker;
@@ -3423,6 +3431,7 @@
if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) {
mUserController.sendForegroundProfileChanged(r.userId);
}
+ updateResumedAppTrace(r);
mLastResumedActivity = r;
mWindowManager.setFocusedApp(r.appToken, true);
@@ -3436,6 +3445,22 @@
reason);
}
+ private void updateResumedAppTrace(@Nullable ActivityRecord resumed) {
+ if (mTracedResumedActivity != null) {
+ Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER,
+ constructResumedTraceName(mTracedResumedActivity.packageName), 0);
+ }
+ if (resumed != null) {
+ Trace.asyncTraceBegin(TRACE_TAG_ACTIVITY_MANAGER,
+ constructResumedTraceName(resumed.packageName), 0);
+ }
+ mTracedResumedActivity = resumed;
+ }
+
+ private String constructResumedTraceName(String packageName) {
+ return "focused app: " + packageName;
+ }
+
@Override
public void setFocusedStack(int stackId) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setFocusedStack()");
@@ -7575,6 +7600,9 @@
if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup();
+ if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
+ clearProfilerLocked();
+ }
}
// We deprecated Build.SERIAL and it is not accessible to
@@ -7659,7 +7687,10 @@
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
}
-
+ if (profilerInfo != null) {
+ profilerInfo.closeFd();
+ profilerInfo = null;
+ }
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
@@ -13073,6 +13104,7 @@
}
mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
mStackSupervisor.goingToSleepLocked();
+ updateResumedAppTrace(null /* resumed */);
updateOomAdjLocked();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 352b757..724dd3f 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -299,7 +299,7 @@
final boolean otherWindowModesLaunching =
mWindowingModeTransitionInfo.size() > 0 && info == null;
- if ((resultCode < 0 || launchedActivity == null || !processSwitch
+ if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
// Failed to launch or it was not a process switch, so we don't care about the timing.
@@ -322,6 +322,14 @@
}
/**
+ * @return True if we should start logging an event for an activity start that returned
+ * {@code resultCode} and that we'll indeed get a windows drawn event.
+ */
+ private boolean isLoggableResultCode(int resultCode) {
+ return resultCode == START_SUCCESS || resultCode == START_TASK_TO_FRONT;
+ }
+
+ /**
* Notifies the tracker that all windows of the app have been drawn.
*/
void notifyWindowsDrawn(int windowingMode, long timestamp) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8c49472..68c47d5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1193,6 +1193,9 @@
}
boolean isFocusable() {
+ if (inSplitScreenPrimaryWindowingMode() && mStackSupervisor.mIsDockMinimized) {
+ return false;
+ }
return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable();
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8f987be..6101420 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3420,7 +3420,7 @@
}
/** Find next proper focusable stack and make it focused. */
- private boolean adjustFocusToNextFocusableStack(String reason) {
+ boolean adjustFocusToNextFocusableStack(String reason) {
return adjustFocusToNextFocusableStack(reason, false /* allowFocusSelf */);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index efc0d7d..be826f7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2455,19 +2455,20 @@
if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
- // If the currently focused stack is in split-screen secondary we would prefer
- // the focus to move to another split-screen secondary stack or fullscreen stack
- // over the primary split screen stack to avoid:
- // - Moving the focus to the primary split-screen stack when it can't be focused
- // because it will be minimized, but AM doesn't know that yet
- // - primary split-screen stack overlapping with a fullscreen stack when a
- // fullscreen stack is higher in z than the next split-screen stack. Assistant
- // stack, I am looking at you...
+ // If the currently focused stack is in split-screen secondary we save off the
+ // top primary split-screen stack as a candidate for focus because we might
+ // prefer focus to move to an other stack to avoid primary split-screen stack
+ // overlapping with a fullscreen stack when a fullscreen stack is higher in z
+ // than the next split-screen stack. Assistant stack, I am looking at you...
// We only move the focus to the primary-split screen stack if there isn't a
// better alternative.
candidate = stack;
continue;
}
+ if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+ // Use the candidate stack since we are now at the secondary split-screen.
+ return candidate;
+ }
return stack;
}
}
@@ -4413,6 +4414,14 @@
void setDockedStackMinimized(boolean minimized) {
mIsDockMinimized = minimized;
+ if (mIsDockMinimized) {
+ final ActivityStack current = getFocusedStack();
+ if (current.inSplitScreenPrimaryWindowingMode()) {
+ // The primary split-screen stack can't be focused while it is minimize, so move
+ // focus to something else.
+ current.adjustFocusToNextFocusableStack("setDockedStackMinimized");
+ }
+ }
}
void wakeUp(String reason) {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 9121568..da56ffd 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
@@ -95,6 +96,8 @@
}
}
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
+
mService.setRunningRemoteAnimation(mCallingPid, true);
mWindowManager.deferSurfaceLayout();
@@ -143,6 +146,9 @@
// If we updated the launch-behind state, update the visibility of the activities after
// we fetch the visible tasks to be controlled by the animation
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT,
+ homeActivity);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 1170148..1575694 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -617,7 +617,8 @@
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
+ " startingWindow=" + mContainer.startingWindow
- + " startingView=" + mContainer.startingSurface);
+ + " startingView=" + mContainer.startingSurface
+ + " Callers=" + Debug.getCallers(5));
// Use the same thread to remove the window as we used to add it, as otherwise we end up
// with things in the view hierarchy being called from different threads.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1f71b8f..88cb54d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2079,6 +2079,13 @@
super.prepareSurfaces();
}
+ /**
+ * @return Whether our {@link #getSurfaceControl} is currently showing.
+ */
+ boolean isSurfaceShowing() {
+ return mLastSurfaceShowing;
+ }
+
boolean isFreezingScreen() {
return mFreezingScreen;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 0b0df6f..3e72a71 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,13 +16,16 @@
package com.android.server.wm;
+import static android.app.ActivityManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
import static com.android.server.wm.proto.RemoteAnimationAdapterWrapperProto.TARGET;
import static com.android.server.wm.proto.AnimationAdapterProto.REMOTE;
@@ -37,6 +40,7 @@
import android.util.Log;
import android.util.Slog;import android.util.proto.ProtoOutputStream;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
@@ -279,6 +283,10 @@
} catch (RemoteException e) {
Slog.e(TAG, "Failed to start recents animation", e);
}
+ final SparseIntArray reasons = new SparseIntArray();
+ reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
+ mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
+ reasons).sendToTarget();
}
void cancelAnimation() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 9310dc4..970a8d7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -247,7 +247,8 @@
// Ensure at least one window for the top app is visible before attempting to take
// a screenshot. Visible here means that the WSA surface is shown and has an alpha
// greater than 0.
- ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
+ ws -> (ws.mAppToken == null || ws.mAppToken.isSurfaceShowing())
+ && ws.mWinAnimator != null && ws.mWinAnimator.getShown()
&& ws.mWinAnimator.mLastAlpha > 0f, true);
if (!hasVisibleChild) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c7ae570..5a3b268 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -566,7 +566,7 @@
@NonNull PasswordMetrics mActivePasswordMetrics = new PasswordMetrics();
int mFailedPasswordAttempts = 0;
boolean mPasswordStateHasBeenSetSinceBoot = false;
- boolean mPasswordValidAtLastCheckpoint = false;
+ boolean mPasswordValidAtLastCheckpoint = true;
int mUserHandle;
int mPasswordOwner = -1;
@@ -3887,23 +3887,28 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.quality != quality) {
metrics.quality = quality;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
}
/**
- * Updates flag in memory that tells us whether the user's password currently satisfies the
- * requirements set by all of the user's active admins. This should be called before
- * {@link #saveSettingsLocked} whenever the password or the admin policies have changed.
+ * Updates a flag that tells us whether the user's password currently satisfies the
+ * requirements set by all of the user's active admins. The flag is updated both in memory
+ * and persisted to disk by calling {@link #saveSettingsLocked}, for the value of the flag
+ * be the correct one upon boot.
+ * This should be called whenever the password or the admin policies have changed.
*/
@GuardedBy("DevicePolicyManagerService.this")
- private void updatePasswordValidityCheckpointLocked(int userHandle) {
- DevicePolicyData policy = getUserData(userHandle);
- policy.mPasswordValidAtLastCheckpoint = isActivePasswordSufficientForUserLocked(
- policy, policy.mUserHandle, false);
+ private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) {
+ final int credentialOwner = getCredentialOwner(userHandle, parent);
+ DevicePolicyData policy = getUserData(credentialOwner);
+ policy.mPasswordValidAtLastCheckpoint =
+ isPasswordSufficientForUserWithoutCheckpointLocked(
+ policy.mActivePasswordMetrics, userHandle, parent);
+
+ saveSettingsLocked(credentialOwner);
}
@Override
@@ -3990,8 +3995,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.length != length) {
metrics.length = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4015,8 +4019,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
}
if (SecurityLog.isLoggingEnabled()) {
@@ -4217,8 +4220,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.upperCase != length) {
metrics.upperCase = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4240,8 +4242,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.lowerCase != length) {
metrics.lowerCase = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4266,8 +4267,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.letters != length) {
metrics.letters = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4292,8 +4292,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.numeric != length) {
metrics.numeric = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4318,8 +4317,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.symbols != length) {
ap.minimumPasswordMetrics.symbols = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4344,8 +4342,7 @@
final PasswordMetrics metrics = ap.minimumPasswordMetrics;
if (metrics.nonLetter != length) {
ap.minimumPasswordMetrics.nonLetter = length;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, parent);
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
@@ -4566,16 +4563,6 @@
private boolean isActivePasswordSufficientForUserLocked(
DevicePolicyData policy, int userHandle, boolean parent) {
- final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
- if (requiredPasswordQuality == PASSWORD_QUALITY_UNSPECIFIED) {
- // A special case is when there is no required password quality, then we just return
- // true since any password would be sufficient. This is for the scenario when a work
- // profile is first created so there is no information about the current password but
- // it should be considered sufficient as there is no password requirement either.
- // This is useful since it short-circuits the password checkpoint for FDE device below.
- return true;
- }
-
if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()
&& !policy.mPasswordStateHasBeenSetSinceBoot) {
// Before user enters their password for the first time after a reboot, return the
@@ -4586,28 +4573,41 @@
return policy.mPasswordValidAtLastCheckpoint;
}
- if (policy.mActivePasswordMetrics.quality < requiredPasswordQuality) {
+ return isPasswordSufficientForUserWithoutCheckpointLocked(
+ policy.mActivePasswordMetrics, userHandle, parent);
+ }
+
+ /**
+ * Returns {@code true} if the password represented by the {@code passwordMetrics} argument
+ * sufficiently fulfills the password requirements for the user corresponding to
+ * {@code userHandle} (or its parent, if {@code parent} is set to {@code true}).
+ */
+ private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
+ PasswordMetrics passwordMetrics, int userHandle, boolean parent) {
+ final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
+
+ if (passwordMetrics.quality < requiredPasswordQuality) {
return false;
}
if (requiredPasswordQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
- && policy.mActivePasswordMetrics.length < getPasswordMinimumLength(
+ && passwordMetrics.length < getPasswordMinimumLength(
null, userHandle, parent)) {
return false;
}
if (requiredPasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
return true;
}
- return policy.mActivePasswordMetrics.upperCase >= getPasswordMinimumUpperCase(
+ return passwordMetrics.upperCase >= getPasswordMinimumUpperCase(
null, userHandle, parent)
- && policy.mActivePasswordMetrics.lowerCase >= getPasswordMinimumLowerCase(
+ && passwordMetrics.lowerCase >= getPasswordMinimumLowerCase(
null, userHandle, parent)
- && policy.mActivePasswordMetrics.letters >= getPasswordMinimumLetters(
+ && passwordMetrics.letters >= getPasswordMinimumLetters(
null, userHandle, parent)
- && policy.mActivePasswordMetrics.numeric >= getPasswordMinimumNumeric(
+ && passwordMetrics.numeric >= getPasswordMinimumNumeric(
null, userHandle, parent)
- && policy.mActivePasswordMetrics.symbols >= getPasswordMinimumSymbols(
+ && passwordMetrics.symbols >= getPasswordMinimumSymbols(
null, userHandle, parent)
- && policy.mActivePasswordMetrics.nonLetter >= getPasswordMinimumNonLetter(
+ && passwordMetrics.nonLetter >= getPasswordMinimumNonLetter(
null, userHandle, parent);
}
@@ -6148,8 +6148,7 @@
try {
synchronized (this) {
policy.mFailedPasswordAttempts = 0;
- updatePasswordValidityCheckpointLocked(userId);
- saveSettingsLocked(userId);
+ updatePasswordValidityCheckpointLocked(userId, /* parent */ false);
updatePasswordExpirationsLocked(userId);
setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index ccde049..4f49a4a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -33,7 +33,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.support.test.filters.FlakyTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -302,7 +301,6 @@
}
@Test
- @FlakyTest(bugId = 37908381)
public void testFocusedWindowMultipleDisplays() throws Exception {
// Create a focusable window and check that focus is calculated correctly
final WindowState window1 =
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index fc459a0..4c70466 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index ac28227..4a4260d 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -22,6 +22,7 @@
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
+#include "format/proto/ProtoSerialize.h"
#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"
@@ -110,7 +111,7 @@
return {};
}
return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
- std::move(manifest));
+ std::move(manifest), ApkFormat::kProto);
}
std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
@@ -153,7 +154,7 @@
return {};
}
return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
- std::move(manifest));
+ std::move(manifest), ApkFormat::kBinary);
}
bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
@@ -205,7 +206,7 @@
}
// The resource table needs to be re-serialized since it might have changed.
- if (path == "resources.arsc") {
+ if (format_ == ApkFormat::kBinary && path == kApkResourceTablePath) {
BigBuffer buffer(4096);
// TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
// with sparse entries) b/35389232.
@@ -215,11 +216,22 @@
}
io::BigBufferInputStream input_stream(&buffer);
- if (!io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kAlign,
+ if (!io::CopyInputStreamToArchive(context,
+ &input_stream,
+ path,
+ ArchiveEntry::kAlign,
writer)) {
return false;
}
-
+ } else if (format_ == ApkFormat::kProto && path == kProtoResourceTablePath) {
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*split_table, &pb_table);
+ if (!io::CopyProtoToArchive(context,
+ &pb_table,
+ path,
+ ArchiveEntry::kAlign, writer)) {
+ return false;
+ }
} else if (manifest != nullptr && path == "AndroidManifest.xml") {
BigBuffer buffer(8192);
XmlFlattenerOptions xml_flattener_options;
@@ -246,9 +258,9 @@
}
ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) {
- if (apk->FindFile("resources.arsc") != nullptr) {
+ if (apk->FindFile(kApkResourceTablePath) != nullptr) {
return ApkFormat::kBinary;
- } else if (apk->FindFile("resources.pb") != nullptr) {
+ } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) {
return ApkFormat::kProto;
} else {
// If the resource table is not present, attempt to read the manifest.
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 81bcecc..41f879d 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -57,11 +57,13 @@
const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest)
+ std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest,
+ const ApkFormat& format)
: source_(source),
apk_(std::move(apk)),
table_(std::move(table)),
- manifest_(std::move(manifest)) {
+ manifest_(std::move(manifest)),
+ format_(format) {
}
io::IFileCollection* GetFileCollection() {
@@ -112,6 +114,7 @@
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
+ ApkFormat format_;
static ApkFormat DetermineApkFormat(io::IFileCollection* apk);
};
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index e1d951f..80eb737 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -104,7 +104,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
FilterChain chain;
@@ -131,7 +131,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
FilterChain chain;
@@ -156,7 +156,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}, kBinary};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
FilterChain chain;