Merge changes from topic "canBubble_isBubble_nuances" into rvc-dev
* changes:
Always open bubble for bubble notifs + fix issue
canBubble only true when it can actually bubble
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index b4a7cd4..9a711d3 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -18,7 +18,6 @@
import static android.provider.DeviceConfig.NAMESPACE_BLOBSTORE;
import static android.text.format.Formatter.FLAG_IEC_UNITS;
import static android.text.format.Formatter.formatFileSize;
-import static android.util.TimeUtils.formatDuration;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -58,18 +57,24 @@
* Job Id for idle maintenance job ({@link BlobStoreIdleJobService}).
*/
public static final int IDLE_JOB_ID = 0xB70B1D7; // 191934935L
- /**
- * Max time period (in millis) between each idle maintenance job run.
- */
- public static final long IDLE_JOB_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
-
- /**
- * Timeout in millis after which sessions with no updates will be deleted.
- */
- public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7);
public static class DeviceConfigProperties {
/**
+ * Denotes the max time period (in millis) between each idle maintenance job run.
+ */
+ public static final String KEY_IDLE_JOB_PERIOD_MS = "idle_job_period_ms";
+ public static final long DEFAULT_IDLE_JOB_PERIOD_MS = TimeUnit.DAYS.toMillis(1);
+ public static long IDLE_JOB_PERIOD_MS = DEFAULT_IDLE_JOB_PERIOD_MS;
+
+ /**
+ * Denotes the timeout in millis after which sessions with no updates will be deleted.
+ */
+ public static final String KEY_SESSION_EXPIRY_TIMEOUT_MS =
+ "session_expiry_timeout_ms";
+ public static final long DEFAULT_SESSION_EXPIRY_TIMEOUT_MS = TimeUnit.DAYS.toMillis(7);
+ public static long SESSION_EXPIRY_TIMEOUT_MS = DEFAULT_SESSION_EXPIRY_TIMEOUT_MS;
+
+ /**
* Denotes how low the limit for the amount of data, that an app will be allowed to acquire
* a lease on, can be.
*/
@@ -119,6 +124,13 @@
}
properties.getKeyset().forEach(key -> {
switch (key) {
+ case KEY_IDLE_JOB_PERIOD_MS:
+ IDLE_JOB_PERIOD_MS = properties.getLong(key, DEFAULT_IDLE_JOB_PERIOD_MS);
+ break;
+ case KEY_SESSION_EXPIRY_TIMEOUT_MS:
+ SESSION_EXPIRY_TIMEOUT_MS = properties.getLong(key,
+ DEFAULT_SESSION_EXPIRY_TIMEOUT_MS);
+ break;
case KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR:
TOTAL_BYTES_PER_APP_LIMIT_FLOOR = properties.getLong(key,
DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR);
@@ -143,6 +155,12 @@
static void dump(IndentingPrintWriter fout, Context context) {
final String dumpFormat = "%s: [cur: %s, def: %s]";
+ fout.println(String.format(dumpFormat, KEY_IDLE_JOB_PERIOD_MS,
+ TimeUtils.formatDuration(IDLE_JOB_PERIOD_MS),
+ TimeUtils.formatDuration(DEFAULT_IDLE_JOB_PERIOD_MS)));
+ fout.println(String.format(dumpFormat, KEY_SESSION_EXPIRY_TIMEOUT_MS,
+ TimeUtils.formatDuration(SESSION_EXPIRY_TIMEOUT_MS),
+ TimeUtils.formatDuration(DEFAULT_SESSION_EXPIRY_TIMEOUT_MS)));
fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
formatFileSize(context, TOTAL_BYTES_PER_APP_LIMIT_FLOOR, FLAG_IEC_UNITS),
formatFileSize(context, DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
@@ -167,6 +185,22 @@
}
/**
+ * Returns the max time period (in millis) between each idle maintenance job run.
+ */
+ public static long getIdleJobPeriodMs() {
+ return DeviceConfigProperties.IDLE_JOB_PERIOD_MS;
+ }
+
+ /**
+ * Returns whether a session is expired or not. A session is considered expired if the session
+ * has not been modified in a while (i.e. SESSION_EXPIRY_TIMEOUT_MS).
+ */
+ public static boolean hasSessionExpired(long sessionLastModifiedMs) {
+ return sessionLastModifiedMs
+ < System.currentTimeMillis() - DeviceConfigProperties.SESSION_EXPIRY_TIMEOUT_MS;
+ }
+
+ /**
* Returns the maximum amount of data that an app can acquire a lease on.
*/
public static long getAppDataBytesLimit() {
@@ -277,9 +311,6 @@
fout.println("XML current version: " + XML_VERSION_CURRENT);
fout.println("Idle job ID: " + IDLE_JOB_ID);
- fout.println("Idle job period: " + formatDuration(IDLE_JOB_PERIOD_MILLIS));
-
- fout.println("Session expiry timeout: " + formatDuration(SESSION_EXPIRY_TIMEOUT_MILLIS));
fout.println("Total bytes per app limit: " + formatFileSize(context,
getAppDataBytesLimit(), FLAG_IEC_UNITS));
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
index 460e776..4b0f719 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java
@@ -16,7 +16,6 @@
package com.android.server.blob;
import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_ID;
-import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_PERIOD_MILLIS;
import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
@@ -60,7 +59,7 @@
new ComponentName(context, BlobStoreIdleJobService.class))
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
- .setPeriodic(IDLE_JOB_PERIOD_MILLIS)
+ .setPeriodic(BlobStoreConfig.getIdleJobPeriodMs())
.build();
jobScheduler.schedule(job);
if (LOGV) {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 9376198..7a27b2c 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -29,10 +29,10 @@
import static android.os.UserHandle.USER_NULL;
import static com.android.server.blob.BlobStoreConfig.LOGV;
-import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
import static com.android.server.blob.BlobStoreConfig.TAG;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs;
+import static com.android.server.blob.BlobStoreConfig.hasSessionExpired;
import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED;
import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED;
import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
@@ -986,9 +986,9 @@
userSessions.removeIf((sessionId, blobStoreSession) -> {
boolean shouldRemove = false;
+ // TODO: handle the case where no content has been written to session yet.
// Cleanup sessions which haven't been modified in a while.
- if (blobStoreSession.getSessionFile().lastModified()
- < System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS) {
+ if (hasSessionExpired(blobStoreSession.getSessionFile().lastModified())) {
shouldRemove = true;
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index e86fdf0..673f668 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -82,7 +82,9 @@
DIMENSION_GUARDRAIL_REACHED = 6,
MULTIPLE_BUCKETS_SKIPPED = 7,
// Not an invalid bucket case, but the bucket is dropped.
- BUCKET_TOO_SMALL = 8
+ BUCKET_TOO_SMALL = 8,
+ // Not an invalid bucket case, but the bucket is skipped.
+ NO_DATA = 9
};
struct Activation {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index f03ce45..dbec24b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -108,7 +108,7 @@
mSkipZeroDiffOutput(metric.skip_zero_diff_output()),
mUseZeroDefaultBase(metric.use_zero_default_base()),
mHasGlobalBase(false),
- mCurrentBucketIsInvalid(false),
+ mCurrentBucketIsSkipped(false),
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
@@ -383,15 +383,12 @@
void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
const BucketDropReason reason) {
- if (!mCurrentBucketIsInvalid) {
+ if (!mCurrentBucketIsSkipped) {
// Only report to StatsdStats once per invalid bucket.
StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
}
- if (!maxDropEventsReached()) {
- mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason));
- }
- mCurrentBucketIsInvalid = true;
+ skipCurrentBucket(dropTimeNs, reason);
}
void ValueMetricProducer::invalidateCurrentBucket(const int64_t dropTimeNs,
@@ -400,6 +397,14 @@
resetBase();
}
+void ValueMetricProducer::skipCurrentBucket(const int64_t dropTimeNs,
+ const BucketDropReason reason) {
+ if (!maxDropEventsReached()) {
+ mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason));
+ }
+ mCurrentBucketIsSkipped = true;
+}
+
void ValueMetricProducer::resetBase() {
for (auto& slice : mCurrentBaseInfo) {
for (auto& baseInfo : slice.second) {
@@ -961,12 +966,10 @@
int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
if (!isBucketLargeEnough) {
- if (!maxDropEventsReached()) {
- mCurrentSkippedBucket.dropEvents.emplace_back(
- buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
- }
+ skipCurrentBucket(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL);
}
- if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
+ bool bucketHasData = false;
+ if (!mCurrentBucketIsSkipped) {
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
@@ -975,14 +978,33 @@
if (bucket.valueIndex.size() > 0) {
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(bucket);
+ bucketHasData = true;
}
}
- } else {
+ }
+
+ if (!bucketHasData && !mCurrentBucketIsSkipped) {
+ skipCurrentBucket(eventTimeNs, BucketDropReason::NO_DATA);
+ }
+
+ if (mCurrentBucketIsSkipped) {
mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
- mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
+ // Fill in the gap if we skipped multiple buckets.
+ mCurrentSkippedBucket.bucketEndTimeNs =
+ numBucketsForward > 1 ? nextBucketStartTimeNs : bucketEndTime;
mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
}
+ // This means that the current bucket was not flushed before a forced bucket split.
+ if (bucketEndTime < nextBucketStartTimeNs && numBucketsForward <= 1) {
+ SkippedBucket bucketInGap;
+ bucketInGap.bucketStartTimeNs = bucketEndTime;
+ bucketInGap.bucketEndTimeNs = nextBucketStartTimeNs;
+ bucketInGap.dropEvents.emplace_back(
+ buildDropEvent(eventTimeNs, BucketDropReason::NO_DATA));
+ mSkippedBuckets.emplace_back(bucketInGap);
+ }
+
appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
initCurrentSlicedBucket(nextBucketStartTimeNs);
// Update the condition timer again, in case we skipped buckets.
@@ -1036,13 +1058,13 @@
// TODO: remove mCurrentBaseInfo entries when obsolete
}
- mCurrentBucketIsInvalid = false;
+ mCurrentBucketIsSkipped = false;
mCurrentSkippedBucket.reset();
// If we do not have a global base when the condition is true,
// we will have incomplete bucket for the next bucket.
if (mUseDiff && !mHasGlobalBase && mCondition) {
- mCurrentBucketIsInvalid = false;
+ mCurrentBucketIsSkipped = false;
}
mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
@@ -1051,7 +1073,7 @@
void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) {
bool isFullBucketReached = eventTimeNs > fullBucketEndTimeNs;
- if (mCurrentBucketIsInvalid) {
+ if (mCurrentBucketIsSkipped) {
if (isFullBucketReached) {
// If the bucket is invalid, we ignore the full bucket since it contains invalid data.
mCurrentFullBucket.clear();
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 751fef2..bb4a661 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -144,6 +144,10 @@
void invalidateCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
void invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
const BucketDropReason reason);
+ // Skips the current bucket without notifying StatsdStats of the skipped bucket.
+ // This should only be called from #flushCurrentBucketLocked. Otherwise, a future event that
+ // causes the bucket to be invalidated will not notify StatsdStats.
+ void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
const int mWhatMatcherIndex;
@@ -250,11 +254,9 @@
// diff against.
bool mHasGlobalBase;
- // Invalid bucket. There was a problem in collecting data in the current bucket so we cannot
- // trust any of the data in this bucket.
- //
- // For instance, one pull failed.
- bool mCurrentBucketIsInvalid;
+ // This is to track whether or not the bucket is skipped for any of the reasons listed in
+ // BucketDropReason, many of which make the bucket potentially invalid.
+ bool mCurrentBucketIsSkipped;
const int64_t mMaxPullDelayNs;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 1121392..6bfa267 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -212,6 +212,8 @@
MULTIPLE_BUCKETS_SKIPPED = 7;
// Not an invalid bucket case, but the bucket is dropped.
BUCKET_TOO_SMALL = 8;
+ // Not an invalid bucket case, but the bucket is skipped.
+ NO_DATA = 9;
};
message DropEvent {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 474aa22..14246cab 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1115,13 +1115,21 @@
EXPECT_EQ(false, curInterval.hasValue);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs},
{bucket2StartTimeNs}, {bucket3StartTimeNs});
+ // The 1st bucket is dropped because of no data
// The 3rd bucket is dropped due to multiple buckets being skipped.
- ASSERT_EQ(1, valueProducer->mSkippedBuckets.size());
- EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
- EXPECT_EQ(bucket4StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
+ ASSERT_EQ(2, valueProducer->mSkippedBuckets.size());
+
+ EXPECT_EQ(bucketStartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
+ EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
ASSERT_EQ(1, valueProducer->mSkippedBuckets[0].dropEvents.size());
- EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
- EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs);
+ EXPECT_EQ(NO_DATA, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
+ EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs);
+
+ EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[1].bucketStartTimeNs);
+ EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].bucketEndTimeNs);
+ ASSERT_EQ(1, valueProducer->mSkippedBuckets[1].dropEvents.size());
+ EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[1].dropEvents[0].reason);
+ EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].dropEvents[0].dropTimeNs);
}
/*
@@ -2214,7 +2222,7 @@
valueProducer->mCondition = ConditionState::kFalse;
valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
- EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
+ EXPECT_EQ(true, valueProducer->mCurrentBucketIsSkipped);
ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size());
@@ -2629,13 +2637,17 @@
vector<shared_ptr<LogEvent>> allData;
allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 4));
+ // Pull fails and arrives late.
valueProducer->onDataPulled(allData, /** fails */ false, bucket3StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9},
{partialBucketSplitTimeNs - bucketStartTimeNs},
{bucketStartTimeNs}, {partialBucketSplitTimeNs});
ASSERT_EQ(1, valueProducer->mSkippedBuckets.size());
+ ASSERT_EQ(2, valueProducer->mSkippedBuckets[0].dropEvents.size());
+ EXPECT_EQ(PULL_FAILED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
+ EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[1].reason);
EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
- EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
+ EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
}
@@ -3464,26 +3476,41 @@
// Condition change event that skips forward by three buckets.
valueProducer->onConditionChanged(false, bucket4StartTimeNs + 10);
+ int64_t dumpTimeNs = bucket4StartTimeNs + 1000;
+
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucket4StartTimeNs + 1000, true /* include recent buckets */, true,
+ valueProducer->onDumpReport(dumpTimeNs, true /* include current buckets */, true,
NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
ASSERT_EQ(0, report.value_metrics().data_size());
- ASSERT_EQ(1, report.value_metrics().skipped_size());
+ ASSERT_EQ(2, report.value_metrics().skipped_size());
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason());
EXPECT_EQ(NanoToMillis(bucket4StartTimeNs + 10), dropEvent.drop_time_millis());
+
+ // This bucket is skipped because a dumpReport with include current buckets is called.
+ // This creates a new bucket from bucket4StartTimeNs to dumpTimeNs in which we have no data
+ // since the condition is false for the entire bucket interval.
+ EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
+ report.value_metrics().skipped(1).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(dumpTimeNs),
+ report.value_metrics().skipped(1).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
+
+ dropEvent = report.value_metrics().skipped(1).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(dumpTimeNs), dropEvent.drop_time_millis());
}
/*
@@ -3544,6 +3571,89 @@
}
/*
+ * Test that NO_DATA dump reason is logged when a flushed bucket contains no data.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
+}
+
+/*
+ * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket
+ * was not flushed in time.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBeforeBucketFlush) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+ // App update event.
+ int64_t appUpdateTimeNs = bucket2StartTimeNs + 1000;
+ valueProducer->notifyAppUpgrade(appUpdateTimeNs);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000; // 10 seconds
+ valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(2, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
+
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ report.value_metrics().skipped(1).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
+ report.value_metrics().skipped(1).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
+
+ dropEvent = report.value_metrics().skipped(1).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
+}
+
+/*
* Test multiple bucket drop events in the same bucket.
*/
TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e0bc764..1b19e12 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14363,6 +14363,21 @@
* @hide
*/
public static final String ADVANCED_BATTERY_USAGE_AMOUNT = "advanced_battery_usage_amount";
+
+ /**
+ * For 5G NSA capable devices, determines whether NR tracking indications are on
+ * when the screen is off.
+ *
+ * Values are:
+ * 0: off - All 5G NSA tracking indications are off when the screen is off.
+ * 1: extended - All 5G NSA tracking indications are on when the screen is off as long as
+ * the device is camped on 5G NSA (5G icon is showing in status bar).
+ * If the device is not camped on 5G NSA, tracking indications are off.
+ * 2: always on - All 5G NSA tracking indications are on whether the screen is on or off.
+ * @hide
+ */
+ public static final String NR_NSA_TRACKING_SCREEN_OFF_MODE =
+ "nr_nsa_tracking_screen_off_mode";
}
/**
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 762895b..023197b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -695,6 +695,8 @@
}
optional Notification notification = 82;
+ optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
message Ntp {
@@ -1060,5 +1062,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 153;
+ // Next tag = 154;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 3d7559b..aae72e5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1131,6 +1131,10 @@
Settings.Global.NSD_ON,
GlobalSettingsProto.NSD_ON);
+ dumpSetting(s, p,
+ Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
+ GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE);
+
final long ntpToken = p.start(GlobalSettingsProto.NTP);
dumpSetting(s, p,
Settings.Global.NTP_SERVER,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index e537b76..fa87b62 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -391,6 +391,7 @@
Settings.Global.NITZ_UPDATE_DIFF,
Settings.Global.NITZ_UPDATE_SPACING,
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
Settings.Global.NSD_ON,
Settings.Global.NTP_SERVER,
Settings.Global.NTP_TIMEOUT,
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 52ace2b..8102043 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -573,6 +573,7 @@
<item name="android:textColor">?attr/wallpaperTextColor</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
+ <item name="android:minWidth">0dp</item>
</style>
<style name="TextAppearance.HeadsUpStatusBarText"
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 23bcb29..8368b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -96,12 +96,6 @@
return new AmbientDisplayConfiguration(context);
}
- /** */
- @Provides
- public Handler provideHandler() {
- return new Handler();
- }
-
@Singleton
@Provides
public DataSaverController provideDataSaverController(NetworkController networkController) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 6572937..95a9006 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -28,6 +28,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.FalsingManager;
@@ -69,7 +70,7 @@
WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
- DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
+ DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 0b04fd0..552fea6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -81,7 +81,7 @@
private fun processDevice(key: String, device: MediaDevice?) {
val enabled = device != null
- val data = MediaDeviceData(enabled, device?.icon, device?.name)
+ val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
listeners.forEach {
it.onMediaDeviceChanged(key, data)
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index cc3ab29d..4b23e67 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -37,6 +37,7 @@
import android.view.InputEventReceiver;
import android.view.InputMonitor;
import android.view.MotionEvent;
+import android.view.ViewConfiguration;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.systemui.R;
@@ -77,10 +78,12 @@
private final Runnable mUpdateMovementBoundsRunnable;
private int mDelta;
+ private float mTouchSlop;
private boolean mAllowGesture;
private boolean mIsAttached;
private boolean mIsEnabled;
private boolean mEnableUserResize;
+ private boolean mThresholdCrossed;
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
@@ -100,6 +103,7 @@
mPipTaskOrganizer = pipTaskOrganizer;
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
+
context.getDisplay().getRealSize(mMaxSize);
reloadResources();
@@ -126,6 +130,7 @@
private void reloadResources() {
final Resources res = mContext.getResources();
mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
private void resetDragCorners() {
@@ -270,7 +275,12 @@
break;
case MotionEvent.ACTION_MOVE:
// Capture inputs
- mInputMonitor.pilferPointers();
+ float dx = Math.abs(ev.getX() - mDownPoint.x);
+ float dy = Math.abs(ev.getY() - mDownPoint.y);
+ if (!mThresholdCrossed && dx > mTouchSlop && dy > mTouchSlop) {
+ mThresholdCrossed = true;
+ mInputMonitor.pilferPointers();
+ }
final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
@@ -288,6 +298,7 @@
mUpdateMovementBoundsRunnable.run();
mCtrlType = CTRL_NONE;
mAllowGesture = false;
+ mThresholdCrossed = false;
});
});
break;
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 7729965..7c9ea6b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -92,6 +92,15 @@
}
/**
+ * @deprecated Please specify @Main or @Background when injecting a Handler or use an Executor.
+ */
+ @Deprecated
+ @Provides
+ public static Handler provideHandler() {
+ return new Handler();
+ }
+
+ /**
* Provide a Background-Thread Executor by default.
*/
@Provides
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index 7b80a6e..c0aef8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
+import android.graphics.drawable.Drawable
import android.media.MediaMetadata
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
@@ -73,6 +74,7 @@
private lateinit var fakeExecutor: FakeExecutor
@Mock private lateinit var listener: MediaDeviceManager.Listener
@Mock private lateinit var device: MediaDevice
+ @Mock private lateinit var icon: Drawable
@Mock private lateinit var route: RoutingSessionInfo
private lateinit var session: MediaSession
private lateinit var metadataBuilder: MediaMetadata.Builder
@@ -89,6 +91,7 @@
// Configure mocks.
whenever(device.name).thenReturn(DEVICE_NAME)
+ whenever(device.iconWithoutBackground).thenReturn(icon)
whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm)
whenever(lmm.getCurrentConnectedDevice()).thenReturn(device)
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
@@ -157,6 +160,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME)
+ assertThat(data.icon).isEqualTo(icon)
}
@Test
@@ -170,6 +174,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME)
+ assertThat(data.icon).isEqualTo(icon)
}
@Test
@@ -183,6 +188,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME)
+ assertThat(data.icon).isEqualTo(icon)
}
@Test
@@ -204,6 +210,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
assertThat(data.name).isNull()
+ assertThat(data.icon).isNull()
}
@Test
@@ -221,6 +228,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
assertThat(data.name).isNull()
+ assertThat(data.icon).isNull()
}
@Test
@@ -238,6 +246,7 @@
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
assertThat(data.name).isNull()
+ assertThat(data.icon).isNull()
}
fun captureCallback(): LocalMediaManager.DeviceCallback {
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index e5c0540..45d53a1 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -68,8 +68,7 @@
public abstract class SystemService {
/** @hide */
- // TODO(b/133242016) STOPSHIP: change to false before R ships
- protected static final boolean DEBUG_USER = true;
+ protected static final boolean DEBUG_USER = false;
/*
* The earliest boot phase the system send to system services on boot.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index eb85db6..dfae702 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1106,12 +1106,14 @@
}
void removeShellRoot(int windowType) {
- ShellRoot root = mShellRoots.get(windowType);
- if (root == null) {
- return;
+ synchronized(mWmService.mGlobalLock) {
+ ShellRoot root = mShellRoots.get(windowType);
+ if (root == null) {
+ return;
+ }
+ root.clear();
+ mShellRoots.remove(windowType);
}
- root.clear();
- mShellRoots.remove(windowType);
}
void setRemoteInsetsController(IDisplayWindowInsetsController controller) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e9aff88..5fa4afd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -334,6 +334,8 @@
private boolean mDragResizing;
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
+ private boolean mResizeForBlastSyncReported;
+
/**
* Special mode that is intended only for the rounded corner overlay: during rotation
* transition, we un-rotate the window token such that the window appears as it did before the
@@ -1370,11 +1372,14 @@
// variables, because mFrameSizeChanged only tracks the width and height changing.
updateLastFrames();
+ // Add a window that is using blastSync to the resizing list if it hasn't been reported
+ // already. This because the window is waiting on a finishDrawing from the client.
if (didFrameInsetsChange
|| winAnimator.mSurfaceResized
|| configChanged
|| dragResizingChanged
- || mReportOrientationChanged) {
+ || mReportOrientationChanged
+ || requestResizeForBlastSync()) {
ProtoLog.v(WM_DEBUG_RESIZE,
"Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b "
+ "dragResizingChanged=%b reportOrientationChanged=%b",
@@ -3483,6 +3488,7 @@
mReportOrientationChanged = false;
mDragResizingChangeReported = true;
mWinAnimator.mSurfaceResized = false;
+ mResizeForBlastSyncReported = true;
mWindowFrames.resetInsetsChanged();
final Rect frame = mWindowFrames.mCompatFrame;
@@ -5500,7 +5506,9 @@
}
long getFrameNumber() {
- return mFrameNumber;
+ // Return the frame number in which changes requested in this layout will be rendered or
+ // -1 if we do not expect the frame to be rendered.
+ return getFrameLw().isEmpty() ? -1 : mFrameNumber;
}
void setFrameNumber(long frameNumber) {
@@ -5733,6 +5741,7 @@
if (!willSync) {
return false;
}
+ mResizeForBlastSyncReported = false;
mLocalSyncId = mBLASTSyncEngine.startSyncSet(this);
addChildrenToSyncSet(mLocalSyncId);
@@ -5777,4 +5786,8 @@
mWaitingListener = null;
return mWinAnimator.finishDrawingLocked(null);
}
+
+ private boolean requestResizeForBlastSync() {
+ return useBLASTSync() && !mResizeForBlastSyncReported;
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
index d338b58..ade01dc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -19,7 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS;
+import static com.android.server.blob.BlobStoreConfig.DeviceConfigProperties.SESSION_EXPIRY_TIMEOUT_MS;
import static com.google.common.truth.Truth.assertThat;
@@ -93,6 +93,7 @@
doReturn(true).when(mBlobsDir).exists();
doReturn(new File[0]).when(mBlobsDir).listFiles();
doReturn(true).when(() -> BlobStoreConfig.hasLeaseWaitTimeElapsed(anyLong()));
+ doCallRealMethod().when(() -> BlobStoreConfig.hasSessionExpired(anyLong()));
mContext = InstrumentationRegistry.getTargetContext();
mHandler = new TestHandler(Looper.getMainLooper());
@@ -236,7 +237,7 @@
public void testHandleIdleMaintenance_deleteStaleSessions() throws Exception {
// Setup sessions
final File sessionFile1 = mock(File.class);
- doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000)
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS + 1000)
.when(sessionFile1).lastModified();
final long sessionId1 = 342;
final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
@@ -256,7 +257,7 @@
mUserSessions.append(sessionId2, session2);
final File sessionFile3 = mock(File.class);
- doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000)
+ doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS - 2000)
.when(sessionFile3).lastModified();
final long sessionId3 = 9484;
final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8ce5daa..e9ed20b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -603,6 +603,29 @@
}
@Test
+ public void testRequestResizeForBlastSync() {
+ final WindowState win = mChildAppWindowAbove;
+ makeWindowVisible(win, win.getParentWindow());
+ win.mLayoutSeq = win.getDisplayContent().mLayoutSeq;
+ win.reportResized();
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).doesNotContain(win);
+
+ // Check that the window is in resizing if using blast sync.
+ win.reportResized();
+ win.prepareForSync(mock(BLASTSyncEngine.TransactionReadyListener.class), 1);
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).contains(win);
+
+ // Don't re-add the window again if it's been reported to the client and still waiting on
+ // the client draw for blast sync.
+ win.reportResized();
+ mWm.mResizingWindows.remove(win);
+ win.updateResizingWindowIfNeeded();
+ assertThat(mWm.mResizingWindows).doesNotContain(win);
+ }
+
+ @Test
public void testGetTransformationMatrix() {
final int PARENT_WINDOW_OFFSET = 1;
final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2;
diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp
index 829c883..5c7c68b 100644
--- a/tests/BlobStoreTestUtils/Android.bp
+++ b/tests/BlobStoreTestUtils/Android.bp
@@ -15,6 +15,9 @@
java_library {
name: "BlobStoreTestUtils",
srcs: ["src/**/*.java"],
- static_libs: ["truth-prebuilt"],
+ static_libs: [
+ "truth-prebuilt",
+ "androidx.test.uiautomator_uiautomator",
+ ],
sdk_version: "test_current",
}
\ No newline at end of file
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
index 6927e86..7cf58e1 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java
@@ -18,12 +18,16 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.Instrumentation;
import android.app.blob.BlobHandle;
import android.app.blob.BlobStoreManager;
import android.app.blob.LeaseInfo;
import android.content.Context;
import android.content.res.Resources;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import androidx.test.uiautomator.UiDevice;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -32,6 +36,8 @@
import java.io.OutputStream;
public class Utils {
+ public static final String TAG = "BlobStoreTest";
+
public static final int BUFFER_SIZE_BYTES = 16 * 1024;
public static final long KB_IN_BYTES = 1000;
@@ -68,7 +74,8 @@
public static void assertLeasedBlobs(BlobStoreManager blobStoreManager,
BlobHandle... expectedBlobHandles) throws IOException {
- assertThat(blobStoreManager.getLeasedBlobs()).containsExactly(expectedBlobHandles);
+ assertThat(blobStoreManager.getLeasedBlobs()).containsExactly(
+ (Object[]) expectedBlobHandles);
}
public static void assertNoLeasedBlobs(BlobStoreManager blobStoreManager)
@@ -141,4 +148,16 @@
assertThat(leaseInfo.getDescriptionResId()).isEqualTo(descriptionResId);
assertThat(leaseInfo.getDescription()).isEqualTo(description);
}
+
+ public static void triggerIdleMaintenance(Instrumentation instrumentation) throws IOException {
+ runShellCmd(instrumentation, "cmd blob_store idle-maintenance");
+ }
+
+ private static String runShellCmd(Instrumentation instrumentation,
+ String cmd) throws IOException {
+ final UiDevice uiDevice = UiDevice.getInstance(instrumentation);
+ final String result = uiDevice.executeShellCommand(cmd);
+ Log.i(TAG, "Output of '" + cmd + "': '" + result + "'");
+ return result;
+ }
}