Merge "Per-test WindowManagerService instance"
diff --git a/api/current.txt b/api/current.txt
index ec16f1e..969d7bd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23371,6 +23371,18 @@
method public void onAudioFocusChange(int);
}
+ public final class AudioPlaybackCaptureConfiguration {
+ }
+
+ public static final class AudioPlaybackCaptureConfiguration.Builder {
+ ctor public AudioPlaybackCaptureConfiguration.Builder();
+ method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
+ method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes);
+ method public android.media.AudioPlaybackCaptureConfiguration build();
+ method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
+ method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes);
+ }
+
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.media.AudioAttributes getAudioAttributes();
@@ -23469,6 +23481,7 @@
ctor public AudioRecord.Builder();
method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
method public android.media.AudioRecord.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration);
method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException;
method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
}
@@ -44259,6 +44272,7 @@
field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 653ef2e..a6699e7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -298,7 +298,7 @@
void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
const StatsdConfig& config) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED);
+ WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS);
OnConfigUpdatedLocked(timestampNs, key, config);
}
@@ -355,6 +355,7 @@
const bool include_current_partial_bucket,
const bool erase_data,
const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
ProtoOutputStream* proto) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
@@ -378,8 +379,10 @@
// Start of ConfigMetricsReport (reports).
uint64_t reportsToken =
proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
- onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
- erase_data, dumpReportReason, proto);
+ onConfigMetricsReportLocked(key, dumpTimeStampNs,
+ include_current_partial_bucket,
+ erase_data, dumpReportReason,
+ dumpLatency, proto);
proto->end(reportsToken);
// End of ConfigMetricsReport (reports).
} else {
@@ -394,10 +397,11 @@
const bool include_current_partial_bucket,
const bool erase_data,
const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
vector<uint8_t>* outData) {
ProtoOutputStream proto;
onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
- dumpReportReason, &proto);
+ dumpReportReason, dumpLatency, &proto);
if (outData != nullptr) {
outData->clear();
@@ -423,6 +427,7 @@
const bool include_current_partial_bucket,
const bool erase_data,
const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
ProtoOutputStream* proto) {
// We already checked whether key exists in mMetricsManagers in
// WriteDataToDisk.
@@ -438,7 +443,7 @@
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
- erase_data, &str_set, proto);
+ erase_data, dumpLatency, &str_set, proto);
// Fill in UidMap if there is at least one metric to report.
// This skips the uid map if it's an empty config.
@@ -492,7 +497,7 @@
}
}
if (configKeysTtlExpired.size() > 0) {
- WriteDataToDiskLocked(CONFIG_RESET);
+ WriteDataToDiskLocked(CONFIG_RESET, NO_TIME_CONSTRAINTS);
resetConfigsLocked(timestampNs, configKeysTtlExpired);
}
}
@@ -501,7 +506,8 @@
std::lock_guard<std::mutex> lock(mMetricsMutex);
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
- WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED);
+ WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED,
+ NO_TIME_CONSTRAINTS);
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
}
@@ -572,14 +578,15 @@
void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
const int64_t timestampNs,
- const DumpReportReason dumpReportReason) {
+ const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency) {
if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
!mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
return;
}
ProtoOutputStream proto;
onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
- true /* erase_data */, dumpReportReason, &proto);
+ true /* erase_data */, dumpReportReason, dumpLatency, &proto);
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
android::base::unique_fd fd(open(file_name.c_str(),
@@ -658,7 +665,8 @@
StorageManager::deleteFile(file_name.c_str());
}
-void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason) {
+void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency) {
const int64_t timeNs = getElapsedRealtimeNs();
// Do not write to disk if we already have in the last few seconds.
// This is to avoid overwriting files that would have the same name if we
@@ -671,13 +679,14 @@
}
mLastWriteTimeNs = timeNs;
for (auto& pair : mMetricsManagers) {
- WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason);
+ WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason, dumpLatency);
}
}
-void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason) {
+void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- WriteDataToDiskLocked(dumpReportReason);
+ WriteDataToDiskLocked(dumpReportReason, dumpLatency);
}
void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index ea9c6e7..e92b897 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -66,10 +66,14 @@
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
const bool include_current_partial_bucket, const bool erase_data,
- const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
+ const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
+ vector<uint8_t>* outData);
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
const bool include_current_partial_bucket, const bool erase_data,
- const DumpReportReason dumpReportReason, ProtoOutputStream* proto);
+ const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
+ ProtoOutputStream* proto);
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
void onAnomalyAlarmFired(
@@ -82,7 +86,8 @@
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
/* Flushes data to disk. Data on memory will be gone after written to disk. */
- void WriteDataToDisk(const DumpReportReason dumpReportReason);
+ void WriteDataToDisk(const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency);
/* Persist metric activation status onto disk. */
void WriteMetricsActivationToDisk(int64_t currentTimeNs);
@@ -153,14 +158,17 @@
void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
- void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
+ void WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency);
void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
- const DumpReportReason dumpReportReason);
+ const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency);
void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
const bool erase_data,
const DumpReportReason dumpReportReason,
+ const DumpLatency dumpLatency,
util::ProtoOutputStream* proto);
/* Check if we should send a broadcast if approaching memory limits and if we're over, we
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c542b62..4deb8bd 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -313,7 +313,9 @@
proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
true /* includeCurrentBucket */, false /* erase_data */,
- ADB_DUMP, &proto);
+ ADB_DUMP,
+ FAST,
+ &proto);
proto.end(reportsListToken);
proto.flush(out);
proto.clear();
@@ -694,7 +696,9 @@
if (good) {
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
- includeCurrentBucket, eraseData, ADB_DUMP, &data);
+ includeCurrentBucket, eraseData, ADB_DUMP,
+ NO_TIME_CONSTRAINTS,
+ &data);
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
dprintf(out, "%c", data[i]);
@@ -758,7 +762,7 @@
status_t StatsService::cmd_write_data_to_disk(int out) {
dprintf(out, "Writing data to disk\n");
- mProcessor->WriteDataToDisk(ADB_DUMP);
+ mProcessor->WriteDataToDisk(ADB_DUMP, NO_TIME_CONSTRAINTS);
return NO_ERROR;
}
@@ -958,7 +962,7 @@
Status StatsService::informDeviceShutdown() {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informDeviceShutdown");
- mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN);
+ mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
return Status::ok();
}
@@ -1000,7 +1004,7 @@
void StatsService::Terminate() {
ALOGI("StatsService::Terminating");
if (mProcessor != nullptr) {
- mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED);
+ mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
}
}
@@ -1017,8 +1021,10 @@
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
ConfigKey configKey(ipc->getCallingUid(), key);
+ // The dump latency does not matter here since we do not include the current bucket, we do not
+ // need to pull any new data anyhow.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
- true /* erase_data */, GET_DATA_CALLED, output);
+ true /* erase_data */, GET_DATA_CALLED, FAST, output);
return Status::ok();
}
@@ -1312,7 +1318,7 @@
StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
if (mProcessor != nullptr) {
ALOGW("Reset statsd upon system server restarts.");
- mProcessor->WriteDataToDisk(STATSCOMPANION_DIED);
+ mProcessor->WriteDataToDisk(STATSCOMPANION_DIED, FAST);
mProcessor->resetConfigs();
}
mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d78647e..62926cb 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5630,7 +5630,7 @@
* frameworks/base/packages/SystemUI/
*/
message AssistGestureStageReported {
- optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
+ optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
}
/**
@@ -5640,8 +5640,8 @@
* frameworks/base/packages/SystemUI/
*/
message AssistGestureFeedbackReported {
- // Whether or not the gesture was used.
- optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
+ // Whether or not the gesture was used.
+ optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
}
/**
@@ -5651,8 +5651,8 @@
* frameworks/base/packages/SystemUI/
*/
message AssistGestureProgressReported {
- // [0,100] progress for the assist gesture.
- optional int32 progress = 1;
+ // [0,100] progress for the assist gesture.
+ optional int32 progress = 1;
}
/*
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e84f88d..96d1447 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -139,13 +139,13 @@
void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
- flushIfNeededLocked(dumpTimeNs);
mPastBuckets.clear();
}
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -319,7 +319,7 @@
return;
}
- flushCurrentBucketLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
// Setup the bucket start time and number.
int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
@@ -328,7 +328,8 @@
(long long)mCurrentBucketStartTimeNs);
}
-void CountMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void CountMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) {
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
CountBucket info;
info.mBucketStartNs = mCurrentBucketStartTimeNs;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 1ac44264..b4a910c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -57,6 +57,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
@@ -78,7 +79,8 @@
// Util function to flush the old packet.
void flushIfNeededLocked(const int64_t& newEventTime) override;
- void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+ void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) override;
std::unordered_map<MetricDimensionKey, std::vector<CountBucket>> mPastBuckets;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index da6b97c..5e4594b 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -456,6 +456,7 @@
void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -581,7 +582,8 @@
mCurrentBucketNum += numBucketsForward;
}
-void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) {
for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
whatIt != mCurrentSlicedDurationTrackerMap.end();) {
for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index ec561b5..f711df2 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -64,6 +64,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
@@ -88,7 +89,8 @@
// Util function to flush the old packet.
void flushIfNeededLocked(const int64_t& eventTime);
- void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+ void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) override;
const DurationMetric_AggregationType mAggregationType;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 3b4af65..5435c84 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -108,6 +108,7 @@
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 96adfdd..74e6bc8 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -48,6 +48,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 6301793..7b001b3 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -184,6 +184,7 @@
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("Gauge metric %lld report now...", (long long)mMetricId);
@@ -528,7 +529,7 @@
return;
}
- flushCurrentBucketLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
// Adjusts the bucket start and end times.
int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
@@ -538,7 +539,8 @@
(long long)mCurrentBucketStartTimeNs);
}
-void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) {
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
GaugeBucket info;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 64a1833..9b99fb1 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -82,8 +82,7 @@
// Flush full buckets on the normal path up to the latest bucket boundary.
flushIfNeededLocked(eventTimeNs);
}
- flushCurrentBucketLocked(eventTimeNs);
- mCurrentBucketStartTimeNs = eventTimeNs;
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
pullAndMatchEventsLocked(eventTimeNs);
}
@@ -99,6 +98,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -119,7 +119,8 @@
// Util function to flush the old packet.
void flushIfNeededLocked(const int64_t& eventTime) override;
- void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+ void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) override;
void pullAndMatchEventsLocked(const int64_t timestampNs);
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 8ab3b06..99cb5d4 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -46,6 +46,16 @@
kActiveOnBoot = 2,
};
+enum DumpLatency {
+ // In some cases, we only have a short time range to do the dump, e.g. statsd is being killed.
+ // We might be able to return all the data in this mode. For instance, pull metrics might need
+ // to be pulled when the current bucket is requested.
+ FAST = 1,
+ // In other cases, it is fine for a dump to take more than a few milliseconds, e.g. config
+ // updates.
+ NO_TIME_CONSTRAINTS = 2
+};
+
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -87,8 +97,7 @@
flushIfNeededLocked(eventTimeNs);
}
// Now flush a partial bucket.
- flushCurrentBucketLocked(eventTimeNs);
- mCurrentBucketStartTimeNs = eventTimeNs;
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
// Don't update the current bucket number so that the anomaly tracker knows this bucket
// is a partial bucket and can merge it with the previous bucket.
};
@@ -135,11 +144,12 @@
void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
- str_set, protoOutput);
+ dumpLatency, str_set, protoOutput);
}
void clearPastBuckets(const int64_t dumpTimeNs) {
@@ -239,6 +249,7 @@
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) = 0;
virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
@@ -270,7 +281,7 @@
*/
virtual void flushLocked(const int64_t& eventTimeNs) {
flushIfNeededLocked(eventTimeNs);
- flushCurrentBucketLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
};
/**
@@ -283,7 +294,8 @@
* flushIfNeededLocked or the app upgrade handler; the caller MUST update the bucket timestamp
* and bucket number as needed.
*/
- virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs){};
+ virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) {};
// Convenience to compute the current bucket's end time, which is always aligned with the
// start time of the metric.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 4851a8d..4b3bfd3 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -217,6 +217,7 @@
void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
@@ -227,10 +228,10 @@
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
if (mHashStringsInReport) {
producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
- str_set, protoOutput);
+ dumpLatency, str_set, protoOutput);
} else {
producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
- nullptr, protoOutput);
+ dumpLatency, nullptr, protoOutput);
}
protoOutput->end(token);
} else {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index eab1f76..3904460 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -121,6 +121,7 @@
virtual void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 3cf378d..e94b75c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -188,13 +188,28 @@
void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
+ flushIfNeededLocked(dumpTimeNs);
if (include_current_partial_bucket) {
- flushLocked(dumpTimeNs);
- } else {
- flushIfNeededLocked(dumpTimeNs);
+ // For pull metrics, we need to do a pull at bucket boundaries. If we do not do that the
+ // current bucket will have incomplete data and the next will have the wrong snapshot to do
+ // a diff against. If the condition is false, we are fine since the base data is reset and
+ // we are not tracking anything.
+ bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
+ if (pullNeeded) {
+ switch (dumpLatency) {
+ case FAST:
+ invalidateCurrentBucket();
+ break;
+ case NO_TIME_CONSTRAINTS:
+ pullAndMatchEventsLocked(dumpTimeNs);
+ break;
+ }
+ }
+ flushCurrentBucketLocked(dumpTimeNs, dumpTimeNs);
}
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
@@ -712,23 +727,21 @@
return;
}
- flushCurrentBucketLocked(eventTimeNs);
-
int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
- mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
- mCurrentBucketNum += numBucketsForward;
+ int64_t nextBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ flushCurrentBucketLocked(eventTimeNs, nextBucketStartTimeNs);
+ mCurrentBucketNum += numBucketsForward;
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
// take base again in future good bucket.
resetBase();
}
- VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
- (long long)mCurrentBucketStartTimeNs);
}
-void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) {
if (mCondition == ConditionState::kUnknown) {
StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
}
@@ -758,6 +771,9 @@
}
initCurrentSlicedBucket();
mCurrentBucketIsInvalid = false;
+ mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
+ VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+ (long long)mCurrentBucketStartTimeNs);
}
ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index f26ad85..696d4fa 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -65,8 +65,7 @@
if (mIsPulled && mCondition) {
pullAndMatchEventsLocked(eventTimeNs - 1);
}
- flushCurrentBucketLocked(eventTimeNs);
- mCurrentBucketStartTimeNs = eventTimeNs;
+ flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
};
protected:
@@ -79,6 +78,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
const bool erase_data,
+ const DumpLatency dumpLatency,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -97,7 +97,8 @@
// Util function to flush the old packet.
void flushIfNeededLocked(const int64_t& eventTime) override;
- void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+ void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+ const int64_t& nextBucketStartTimeNs) override;
void dropDataLocked(const int64_t dropTimeNs) override;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 4579ca6..88aa180 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -173,7 +173,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -204,7 +204,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -235,7 +235,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -269,21 +269,21 @@
ConfigMetricsReportList output;
// Dump report WITHOUT erasing data.
- processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, &bytes);
+ processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST, &bytes);
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_EQ(output.reports_size(), 1);
EXPECT_EQ(output.reports(0).metrics_size(), 1);
EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
// Dump report WITH erasing data. There should be data since we didn't previously erase it.
- processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, &bytes);
+ processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
output.ParseFromArray(bytes.data(), bytes.size());
EXPECT_EQ(output.reports_size(), 1);
EXPECT_EQ(output.reports(0).metrics_size(), 1);
EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
// Dump report again. There should be no data since we erased it.
- processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, &bytes);
+ processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
output.ParseFromArray(bytes.data(), bytes.size());
// We don't care whether statsd has a report, as long as it has no count metrics in it.
bool noData = output.reports_size() == 0
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a9841c9..3382525 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -147,7 +147,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -295,7 +295,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index a8914da..e4186b7 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -212,7 +212,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, &buffer);
+ true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -548,7 +548,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, &buffer);
+ true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -798,7 +798,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, &buffer);
+ true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 621b6ed..f3ecd56 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -131,7 +131,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -347,7 +347,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -531,7 +531,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -733,7 +733,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 9f8acaf..489bb0b 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -143,7 +143,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, &buffer);
+ true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -438,7 +438,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- true, ADB_DUMP, &buffer);
+ true, ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -659,7 +659,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 24a9980..946eccf 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -125,7 +125,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -248,7 +248,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -352,7 +352,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 3af8212..cd80310 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -150,7 +150,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 85d8a56..7fb43f8a 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -211,7 +211,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 9349c85..78fb391 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -200,7 +200,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -319,7 +319,7 @@
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index aee0c1f..ef3643f 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
- true /* erase_data */, ADB_DUMP, &output);
+ true /* erase_data */, ADB_DUMP, FAST, &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index f3c4e12..cdb5a78 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -121,7 +121,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -228,7 +228,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 16be3d7..e13bf14 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -128,7 +128,7 @@
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -165,7 +165,7 @@
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -216,7 +216,7 @@
}
processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -249,7 +249,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -279,7 +279,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -325,7 +325,7 @@
}
processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
- ADB_DUMP, &buffer);
+ ADB_DUMP, FAST, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 7e7ffed..a9d2c88 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2797,7 +2797,6 @@
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
}
-
TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
ValueMetric metric;
metric.set_id(metricId);
@@ -2864,6 +2863,187 @@
EXPECT_EQ(true, valueProducer.mHasGlobalBase);
}
+static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
+ vector<uint8_t> bytes;
+ bytes.resize(proto->size());
+ size_t pos = 0;
+ auto iter = proto->data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&((bytes)[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ StatsLogReport report;
+ report.ParseFromArray(bytes.data(), bytes.size());
+ return report;
+}
+
+TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initial pull.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(tagId);
+ event->write(1);
+ event->write(1);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer.onDumpReport(bucketStartTimeNs + 10,
+ true /* include recent buckets */, true,
+ FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ // Bucket is invalid since we did not pull when dump report was called.
+ EXPECT_EQ(0, report.value_metrics().data_size());
+}
+
+TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initial pull.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(tagId);
+ event->write(1);
+ event->write(1);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(tagId);
+ event->write(2);
+ event->write(2);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer.onDumpReport(bucket4StartTimeNs,
+ false /* include recent buckets */, true,
+ FAST, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ // Previous bucket is part of the report.
+ EXPECT_EQ(1, report.value_metrics().data_size());
+ EXPECT_EQ(0, report.value_metrics().data(0).bucket_info(0).bucket_num());
+}
+
+TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initial pull.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(tagId);
+ event->write(1);
+ event->write(1);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event->write(tagId);
+ event->write(3);
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer.onDumpReport(bucketStartTimeNs + 10,
+ true /* include recent buckets */, true,
+ NO_TIME_CONSTRAINTS, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_EQ(1, report.value_metrics().data_size());
+ EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
+ EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+}
+
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 1de8117..de378b0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -398,8 +398,8 @@
}
}
- /**
- * See com.android.internal.os.SystemZygoteInit.readArgumentList()
+ /*
+ * See com.android.internal.os.ZygoteArguments.parseArgs()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index ce83a57..792eda7 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -85,6 +85,18 @@
private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() {
@Override
+ public void onConnected() {
+ mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnConnected,
+ AugmentedAutofillService.this));
+ }
+
+ @Override
+ public void onDisconnected() {
+ mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnDisconnected,
+ AugmentedAutofillService.this));
+ }
+
+ @Override
public void onFillRequest(int sessionId, IBinder client, int taskId,
ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
long requestTime, IFillCallback callback) {
@@ -174,6 +186,14 @@
public void onDisconnected() {
}
+ private void handleOnConnected() {
+ onConnected();
+ }
+
+ private void handleOnDisconnected() {
+ onDisconnected();
+ }
+
private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
@NonNull ComponentName componentName, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime,
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index fb6912a..5096811 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -31,7 +31,8 @@
* @hide
*/
oneway interface IAugmentedAutofillService {
-
+ void onConnected();
+ void onDisconnected();
void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
in ComponentName activityComponent, in AutofillId focusedId,
in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
diff --git a/core/java/android/view/CompositionSamplingListener.java b/core/java/android/view/CompositionSamplingListener.java
new file mode 100644
index 0000000..e4309a6
--- /dev/null
+++ b/core/java/android/view/CompositionSamplingListener.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Rect;
+import android.os.IBinder;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Listener for sampling the result of the screen composition.
+ * {@hide}
+ */
+public abstract class CompositionSamplingListener {
+
+ private final long mNativeListener;
+ private final Executor mExecutor;
+
+ public CompositionSamplingListener(Executor executor) {
+ mExecutor = executor;
+ mNativeListener = nativeCreate(this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mNativeListener != 0) {
+ unregister(this);
+ nativeDestroy(mNativeListener);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Reports a luma sample from the registered region.
+ */
+ public abstract void onSampleCollected(float medianLuma);
+
+ /**
+ * Registers a sampling listener.
+ */
+ public static void register(CompositionSamplingListener listener,
+ int displayId, IBinder stopLayer, Rect samplingArea) {
+ Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY,
+ "default display only for now");
+ nativeRegister(listener.mNativeListener, stopLayer, samplingArea.left, samplingArea.top,
+ samplingArea.right, samplingArea.bottom);
+ }
+
+ /**
+ * Unregisters a sampling listener.
+ */
+ public static void unregister(CompositionSamplingListener listener) {
+ nativeUnregister(listener.mNativeListener);
+ }
+
+ /**
+ * Dispatch the collected sample.
+ *
+ * Called from native code on a binder thread.
+ */
+ private static void dispatchOnSampleCollected(CompositionSamplingListener listener,
+ float medianLuma) {
+ listener.mExecutor.execute(() -> listener.onSampleCollected(medianLuma));
+ }
+
+ private static native long nativeCreate(CompositionSamplingListener thiz);
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeRegister(long ptr, IBinder stopLayer,
+ int samplingAreaLeft, int top, int right, int bottom);
+ private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a6b40ed..e9b1683 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -369,6 +369,11 @@
public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
"smart_suggestion_supported_modes";
+ /** @hide */
+ public static final int RESULT_OK = 0;
+ /** @hide */
+ public static final int RESULT_CODE_NOT_SERVICE = -1;
+
/**
* Makes an authentication id from a request id and a dataset id.
*
@@ -1789,7 +1794,11 @@
@Deprecated
public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
@Nullable List<ComponentName> activities) {
- // TODO(b/123100824): implement
+ setAugmentedAutofillWhitelist(toSet(packages), toSet(activities));
+ }
+
+ private <T> ArraySet<T> toSet(@Nullable List<T> set) {
+ return set == null ? null : new ArraySet<T>(set);
}
/**
@@ -1814,7 +1823,32 @@
@TestApi
public void setAugmentedAutofillWhitelist(@Nullable Set<String> packages,
@Nullable Set<ComponentName> activities) {
- // TODO(b/123100824): implement
+ if (!hasAutofillFeature()) {
+ return;
+ }
+
+ final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+ final int resultCode;
+ try {
+ mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities),
+ resultReceiver);
+ resultCode = resultReceiver.getIntResult();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ switch (resultCode) {
+ case RESULT_OK:
+ return;
+ case RESULT_CODE_NOT_SERVICE:
+ throw new SecurityException("caller is not user's Augmented Autofill Service");
+ default:
+ Log.wtf(TAG, "setAugmentedAutofillWhitelist(): received invalid result: "
+ + resultCode);
+ }
+ }
+
+ private <T> ArrayList<T> toList(@Nullable Set<T> set) {
+ return set == null ? null : new ArrayList<T>(set);
}
private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 26aeba5..9e6a4af 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -63,4 +63,6 @@
void getAutofillServiceComponentName(in IResultReceiver result);
void getAvailableFieldClassificationAlgorithms(in IResultReceiver result);
void getDefaultFieldClassificationAlgorithm(in IResultReceiver result);
+ void setAugmentedAutofillWhitelist(in List<String> packages, in List<ComponentName> activities,
+ in IResultReceiver result);
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 22884ac..0604ab2 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -767,17 +767,6 @@
* @throws IOException passed straight through
*/
static String[] readArgumentList(BufferedReader socketReader) throws IOException {
-
- /**
- * See android.os.Process.zygoteSendArgsAndGetPid()
- * Presently the wire format to the zygote process is:
- * a) a count of arguments (argc, in essence)
- * b) a number of newline-separated argument strings equal to count
- *
- * After the zygote process reads these it will write the pid of
- * the child or -1 on failure.
- */
-
int argc;
try {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index e6bcd37..c24a9e0 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -217,8 +217,17 @@
* Per security review bug #1112214, duplicate args are disallowed in critical cases to make
* injection harder.
*/
- private void parseArgs(String[] args)
- throws IllegalArgumentException {
+ private void parseArgs(String[] args) throws IllegalArgumentException {
+ /*
+ * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
+ * Presently the wire format to the zygote process is:
+ * a) a count of arguments (argc, in essence)
+ * b) a number of newline-separated argument strings equal to count
+ *
+ * After the zygote process reads these it will write the pid of
+ * the child or -1 on failure.
+ */
+
int curArg = 0;
boolean seenRuntimeArgs = false;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 30e9937..c309f27 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -62,6 +62,7 @@
"android_graphics_drawable_AnimatedVectorDrawable.cpp",
"android_graphics_drawable_VectorDrawable.cpp",
"android_graphics_Picture.cpp",
+ "android_view_CompositionSamplingListener.cpp",
"android_view_DisplayEventReceiver.cpp",
"android_view_DisplayListCanvas.cpp",
"android_view_TextureLayer.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 019ade9..0938e56 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -163,6 +163,7 @@
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_SurfaceControl(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
+extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
extern int register_android_view_ThreadedRenderer(JNIEnv* env);
extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
@@ -1415,6 +1416,7 @@
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_SurfaceControl),
REG_JNI(register_android_view_SurfaceSession),
+ REG_JNI(register_android_view_CompositionSamplingListener),
REG_JNI(register_android_view_TextureView),
REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
diff --git a/core/jni/android_view_CompositionSamplingListener.cpp b/core/jni/android_view_CompositionSamplingListener.cpp
new file mode 100644
index 0000000..283ba0d
--- /dev/null
+++ b/core/jni/android_view_CompositionSamplingListener.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CompositionSamplingListener"
+
+#include "android_util_Binder.h"
+
+#include <nativehelper/JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <binder/IServiceManager.h>
+
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+namespace {
+
+struct {
+ jclass mClass;
+ jmethodID mDispatchOnSampleCollected;
+} gListenerClassInfo;
+
+struct CompositionSamplingListener : public BnRegionSamplingListener {
+ CompositionSamplingListener(JNIEnv* env, jobject listener)
+ : mListener(env->NewGlobalRef(listener)) {}
+
+ void onSampleCollected(float medianLuma) override {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onSampleCollected.");
+
+ env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+ gListenerClassInfo.mDispatchOnSampleCollected, mListener,
+ static_cast<jfloat>(medianLuma));
+ if (env->ExceptionCheck()) {
+ ALOGE("CompositionSamplingListener.onSampleCollected() failed.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ }
+
+protected:
+ virtual ~CompositionSamplingListener() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mListener);
+ }
+
+private:
+ jobject mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+ CompositionSamplingListener* listener = new CompositionSamplingListener(env, obj);
+ listener->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+ CompositionSamplingListener* listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+ listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jobject stopLayerTokenObj,
+ jint left, jint top, jint right, jint bottom) {
+ sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+ sp<IBinder> stopLayerHandle = ibinderForJavaObject(env, stopLayerTokenObj);
+
+ // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
+ sp<ISurfaceComposer> composer;
+ if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
+ jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
+ return;
+ }
+
+ composer->addRegionSamplingListener(
+ Rect(left, top, right, bottom), stopLayerHandle, listener);
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+ sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+
+ // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
+ sp<ISurfaceComposer> composer;
+ if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
+ jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
+ return;
+ }
+
+ composer->removeRegionSamplingListener(listener);
+}
+
+const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeCreate", "(Landroid/view/CompositionSamplingListener;)J",
+ (void*)nativeCreate },
+ { "nativeDestroy", "(J)V",
+ (void*)nativeDestroy },
+ { "nativeRegister", "(JLandroid/os/IBinder;IIII)V",
+ (void*)nativeRegister },
+ { "nativeUnregister", "(J)V",
+ (void*)nativeUnregister }
+};
+
+} // namespace
+
+int register_android_view_CompositionSamplingListener(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/CompositionSamplingListener",
+ gMethods, NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz = env->FindClass("android/view/CompositionSamplingListener");
+ gListenerClassInfo.mDispatchOnSampleCollected = env->GetStaticMethodID(
+ clazz, "dispatchOnSampleCollected", "(Landroid/view/CompositionSamplingListener;F)V");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
index 8c5841a..012dcb2 100644
--- a/core/proto/android/hardware/sensor/assist/enums.proto
+++ b/core/proto/android/hardware/sensor/assist/enums.proto
@@ -21,14 +21,14 @@
option java_multiple_files = true;
enum AssistGestureStageEnum {
- ASSIST_GESTURE_STAGE_UNKNOWN = 0;
- ASSIST_GESTURE_STAGE_PROGRESS = 1;
- ASSIST_GESTURE_STAGE_PRIMED = 2;
- ASSIST_GESTURE_STAGE_DETECTED = 3;
+ ASSIST_GESTURE_STAGE_UNKNOWN = 0;
+ ASSIST_GESTURE_STAGE_PROGRESS = 1;
+ ASSIST_GESTURE_STAGE_PRIMED = 2;
+ ASSIST_GESTURE_STAGE_DETECTED = 3;
}
enum AssistGestureFeedbackEnum {
- ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
- ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
- ASSIST_GESTURE_FEEDBACK_USED = 2;
+ ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
+ ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
+ ASSIST_GESTURE_FEEDBACK_USED = 2;
}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java
new file mode 100644
index 0000000..75a2e8a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.graphics.Rect;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class CompositionSamplingListenerTest {
+
+ @Test
+ public void testRegisterUnregister() {
+ CompositionSamplingListener.register(mListener, DEFAULT_DISPLAY, new Binder(),
+ new Rect(1, 1, 10, 10));
+ CompositionSamplingListener.unregister(mListener);
+ }
+
+ private CompositionSamplingListener mListener = new CompositionSamplingListener(Runnable::run) {
+ @Override
+ public void onSampleCollected(float medianLuma) {
+ // Ignore
+ }
+ };
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f996d38..7de7f8f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3188,6 +3188,10 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int registerAudioPolicy(@NonNull AudioPolicy policy) {
+ return registerAudioPolicyStatic(policy);
+ }
+
+ static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
if (policy == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy argument");
}
@@ -3214,6 +3218,10 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
+ unregisterAudioPolicyAsyncStatic(policy);
+ }
+
+ static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
if (policy == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy argument");
}
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
new file mode 100644
index 0000000..22f14ae
--- /dev/null
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Configuration for capturing audio played by other apps.
+ *
+ * <p>An example for creating a capture configuration for capturing all media playback:
+ *
+ * <pre>
+ * AudioAttributes mediaAttr = new AudioAttributes.Builder()
+ * .setUsage(AudioAttributes.USAGE_MEDIA)
+ * .build();
+ * AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder()
+ * .addMatchingUsage(mediaAttr)
+ * .build();
+ * AudioRecord record = new AudioRecord.Builder()
+ * .setPlaybackCaptureConfig(config)
+ * .build();
+ * </pre>
+ *
+ * @see AudioRecord.Builder#setPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration)
+ */
+public final class AudioPlaybackCaptureConfiguration {
+
+ private final AudioMixingRule mAudioMixingRule;
+
+ private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule) {
+ mAudioMixingRule = audioMixingRule;
+ }
+
+ /**
+ * Returns a mix that routes audio back into the app while still playing it from the speakers.
+ *
+ * @param audioFormat The format in which to capture the audio.
+ */
+ AudioMix createAudioMix(AudioFormat audioFormat) {
+ return new AudioMix.Builder(mAudioMixingRule)
+ .setFormat(audioFormat)
+ .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER)
+ .build();
+ }
+
+ /** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */
+ public static final class Builder {
+
+ private static final int MATCH_TYPE_UNSPECIFIED = 0;
+ private static final int MATCH_TYPE_INCLUSIVE = 1;
+ private static final int MATCH_TYPE_EXCLUSIVE = 2;
+
+ private static final String ERROR_MESSAGE_MISMATCHED_RULES =
+ "Inclusive and exclusive usage rules cannot be combined";
+
+ private final AudioMixingRule.Builder mAudioMixingRuleBuilder;
+ private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED;
+ private int mUidMatchType = MATCH_TYPE_UNSPECIFIED;
+
+ public Builder() {
+ mAudioMixingRuleBuilder = new AudioMixingRule.Builder();
+ }
+
+ /**
+ * Only capture audio output with the given {@link AudioAttributes}.
+ *
+ * <p>If called multiple times, will capture audio output that matches any of the given
+ * attributes.
+ *
+ * @throws IllegalStateException if called in conjunction with
+ * {@link #excludeUsage(AudioAttributes)}.
+ */
+ public Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) {
+ Preconditions.checkNotNull(audioAttributes);
+ Preconditions.checkState(
+ mUsageMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder
+ .addRule(audioAttributes, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+ mUsageMatchType = MATCH_TYPE_INCLUSIVE;
+ return this;
+ }
+
+ /**
+ * Only capture audio output by app with the matching {@code uid}.
+ *
+ * <p>If called multiple times, will capture audio output by apps whose uid is any of the
+ * given uids.
+ *
+ * @throws IllegalStateException if called in conjunction with {@link #excludeUid(int)}.
+ */
+ public Builder addMatchingUid(int uid) {
+ Preconditions.checkState(
+ mUidMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+ mUidMatchType = MATCH_TYPE_INCLUSIVE;
+ return this;
+ }
+
+ /**
+ * Only capture audio output that does not match the given {@link AudioAttributes}.
+ *
+ * <p>If called multiple times, will capture audio output that does not match any of the
+ * given attributes.
+ *
+ * @throws IllegalStateException if called in conjunction with
+ * {@link #addMatchingUsage(AudioAttributes)}.
+ */
+ public Builder excludeUsage(@NonNull AudioAttributes audioAttributes) {
+ Preconditions.checkNotNull(audioAttributes);
+ Preconditions.checkState(
+ mUsageMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder.excludeRule(audioAttributes,
+ AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+ mUsageMatchType = MATCH_TYPE_EXCLUSIVE;
+ return this;
+ }
+
+ /**
+ * Only capture audio output by apps that do not have the matching {@code uid}.
+ *
+ * <p>If called multiple times, will capture audio output by apps whose uid is not any of
+ * the given uids.
+ *
+ * @throws IllegalStateException if called in conjunction with {@link #addMatchingUid(int)}.
+ */
+ public Builder excludeUid(int uid) {
+ Preconditions.checkState(
+ mUidMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+ mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+ mUidMatchType = MATCH_TYPE_EXCLUSIVE;
+ return this;
+ }
+
+ /**
+ * Builds the configuration instance.
+ *
+ * @throws UnsupportedOperationException if the parameters set are incompatible.
+ */
+ public AudioPlaybackCaptureConfiguration build() {
+ return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build());
+ }
+ }
+}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 24a3a9b..10accf2 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -24,6 +24,8 @@
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioPolicy;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -37,6 +39,7 @@
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -182,6 +185,8 @@
//---------------------------------------------------------
// Member variables
//--------------------
+ private AudioPolicy mAudioCapturePolicy;
+
/**
* The audio data sampling rate in Hz.
* Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
@@ -429,6 +434,16 @@
}
/**
+ * Sets an {@link AudioPolicy} to automatically unregister when the record is released.
+ *
+ * <p>This is to prevent users of the audio capture API from having to manually unregister the
+ * policy that was used to create the record.
+ */
+ private void unregisterAudioPolicyOnRelease(AudioPolicy audioPolicy) {
+ mAudioCapturePolicy = audioPolicy;
+ }
+
+ /**
* @hide
*/
/* package */ void deferred_connect(long nativeRecordInJavaObj) {
@@ -491,6 +506,11 @@
* the minimum buffer size for the source is used.
*/
public static class Builder {
+
+ private static final String ERROR_MESSAGE_SOURCE_MISMATCH =
+ "Cannot both set audio source and set playback capture config";
+
+ private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration;
private AudioAttributes mAttributes;
private AudioFormat mFormat;
private int mBufferSizeInBytes;
@@ -509,6 +529,9 @@
* @throws IllegalArgumentException
*/
public Builder setAudioSource(int source) throws IllegalArgumentException {
+ Preconditions.checkState(
+ mAudioPlaybackCaptureConfiguration == null,
+ ERROR_MESSAGE_SOURCE_MISMATCH);
if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
(source > MediaRecorder.getAudioSourceMax()) ) {
throw new IllegalArgumentException("Invalid audio source " + source);
@@ -578,6 +601,25 @@
}
/**
+ * Sets the {@link AudioRecord} to record audio played by other apps.
+ *
+ * @param config Defines what apps to record audio from (i.e., via either their uid or
+ * the type of audio).
+ * @throws IllegalStateException if called in conjunction with {@link #setAudioSource(int)}.
+ * @throws NullPointerException if {@code config} is null.
+ */
+ public Builder setAudioPlaybackCaptureConfig(
+ @NonNull AudioPlaybackCaptureConfiguration config) {
+ Preconditions.checkNotNull(
+ config, "Illegal null AudioPlaybackCaptureConfiguration argument");
+ Preconditions.checkState(
+ mAttributes == null,
+ ERROR_MESSAGE_SOURCE_MISMATCH);
+ mAudioPlaybackCaptureConfiguration = config;
+ return this;
+ }
+
+ /**
* @hide
* To be only used by system components.
* @param sessionId ID of audio session the AudioRecord must be attached to, or
@@ -595,6 +637,15 @@
return this;
}
+ private AudioRecord buildAudioPlaybackCaptureRecord() {
+ AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
+ AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
+ .addMix(audioMix).build();
+ AudioRecord record = audioPolicy.createAudioRecordSink(audioMix);
+ record.unregisterAudioPolicyOnRelease(audioPolicy);
+ return record;
+ }
+
/**
* @return a new {@link AudioRecord} instance successfully initialized with all
* the parameters set on this <code>Builder</code>.
@@ -603,6 +654,10 @@
* or if the device was not available.
*/
public AudioRecord build() throws UnsupportedOperationException {
+ if (mAudioPlaybackCaptureConfiguration != null) {
+ return buildAudioPlaybackCaptureRecord();
+ }
+
if (mFormat == null) {
mFormat = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
@@ -757,6 +812,9 @@
} catch(IllegalStateException ise) {
// don't raise an exception, we're releasing the resources.
}
+ if (mAudioCapturePolicy != null) {
+ AudioManager.unregisterAudioPolicyAsyncStatic(mAudioCapturePolicy);
+ }
native_release();
mState = STATE_UNINITIALIZED;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
index 8077431..efa4387 100644
--- a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
+++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
@@ -16,25 +16,21 @@
package com.android.systemui.notifications;
+import android.app.ActivityManager;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
-import android.app.ActivityManager;
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.drivingstate.CarUxRestrictionsManager;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.GestureDetector;
@@ -95,28 +91,12 @@
private static int sSettleOpenPercentage;
private static int sSettleClosePercentage;
- private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_USER_SWITCHED)) {
- mCarNotificationListener.registerAsSystemService(mContext,
- mCarUxRestrictionManagerWrapper,
- mClickHandlerFactory);
- inflateNotificationContent();
- }
- }
- };
-
/**
* Inits the window that hosts the notifications and establishes the connections
* to the car related services.
*/
@Override
public void start() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
sSettleOpenPercentage = mContext.getResources().getInteger(
R.integer.notification_settle_open_percentage);
sSettleClosePercentage = mContext.getResources().getInteger(
@@ -133,11 +113,12 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
launchResult -> {
if (launchResult == ActivityManager.START_TASK_TO_FRONT
- || launchResult == ActivityManager.START_SUCCESS) {
+ || launchResult == ActivityManager.START_SUCCESS){
closeCarNotifications(DEFAULT_FLING_VELOCITY);
}
});
-
+ mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
+ mClickHandlerFactory);
mCar = Car.createCar(mContext, mCarConnectionListener);
mCar.connect();
NotificationGestureListener gestureListener = new NotificationGestureListener();
@@ -150,6 +131,8 @@
mCarNotificationWindow
.setBackgroundColor(mContext.getColor(R.color.notification_shade_background_color));
+ inflateNotificationContent();
+
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
@@ -220,7 +203,7 @@
// There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
// to set the initial click state.
mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
mNotificationListAtBottomAtTimeOfTouch = false;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -271,7 +254,7 @@
public boolean onTouch(View v, MotionEvent event) {
// reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
// get the up event
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
mNotificationListAtBottomAtTimeOfTouch = false;
}
boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
@@ -355,7 +338,7 @@
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
- || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
+ || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){
// swipe was not vertical or was not fast enough
return false;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index e6acfbe..39da194 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -51,7 +51,7 @@
* this method to avoid synchronization issues.
*/
public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
- if (mTargetViewRootImpl == null) {
+ if (mTargetViewRootImpl == null || mTargetViewRootImpl.getView() == null) {
return;
}
mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 152b9fc..4d89a39 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -43,6 +43,8 @@
static final String TAG = "DozeMachine";
static final boolean DEBUG = DozeService.DEBUG;
+ private static final String REASON_CHANGE_STATE = "DozeMachine#requestState";
+ private static final String REASON_HELD_FOR_STATE = "DozeMachine#heldForState";
public enum State {
/** Default state. Transition to INITIALIZED to get Doze going. */
@@ -167,14 +169,14 @@
boolean runNow = !isExecutingTransition();
mQueuedRequests.add(requestedState);
if (runNow) {
- mWakeLock.acquire();
+ mWakeLock.acquire(REASON_CHANGE_STATE);
for (int i = 0; i < mQueuedRequests.size(); i++) {
// Transitions in Parts can call back into requestState, which will
// cause mQueuedRequests to grow.
transitionTo(mQueuedRequests.get(i), pulseReason);
}
mQueuedRequests.clear();
- mWakeLock.release();
+ mWakeLock.release(REASON_CHANGE_STATE);
}
}
@@ -311,10 +313,10 @@
private void updateWakeLockState(State newState) {
boolean staysAwake = newState.staysAwake();
if (mWakeLockHeldForCurrentState && !staysAwake) {
- mWakeLock.release();
+ mWakeLock.release(REASON_HELD_FOR_STATE);
mWakeLockHeldForCurrentState = false;
} else if (!mWakeLockHeldForCurrentState && staysAwake) {
- mWakeLock.acquire();
+ mWakeLock.acquire(REASON_HELD_FOR_STATE);
mWakeLockHeldForCurrentState = true;
}
}
@@ -336,6 +338,7 @@
public void dump(PrintWriter pw) {
pw.print(" state="); pw.println(mState);
pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
+ pw.print(" wakeLock="); pw.println(mWakeLock);
pw.println("Parts:");
for (Part p : mParts) {
p.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index f14d396..368451a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -57,7 +57,7 @@
mDozeService = service;
mHandler = handler;
mParameters = parameters;
- mWakeLock = new SettableWakeLock(wakeLock);
+ mWakeLock = new SettableWakeLock(wakeLock, TAG);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index e207cb1..70bf903 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -348,7 +348,7 @@
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
mHandler);
mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
- mWakeLock.acquire();
+ mWakeLock.acquire(TAG);
mRegistered = true;
}
@@ -383,7 +383,7 @@
}
onProximityResult(result);
if (wasRegistered) {
- mWakeLock.release();
+ mWakeLock.release(TAG);
}
mFinished = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 85d975f..b03b872 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -419,17 +419,16 @@
return KeyguardUpdateMonitor.getInstance(getContext());
}
+ /**
+ * Called whenever new media metadata is available.
+ * @param metadata New metadata.
+ */
@Override
public void onMetadataChanged(MediaMetadata metadata) {
- final boolean notify;
synchronized (this) {
- boolean neededMedia = needsMediaLocked();
mMediaMetaData = metadata;
- notify = neededMedia != needsMediaLocked();
}
- if (notify) {
- notifyChange();
- }
+ notifyChange();
}
protected void notifyChange() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 164f582..a9fe3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -130,7 +130,7 @@
mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
mLockIcon = lockIcon;
- mWakeLock = new SettableWakeLock(wakeLock);
+ mWakeLock = new SettableWakeLock(wakeLock, TAG);
Resources res = context.getResources();
mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
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 ee1e3c0..7bbd3b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -340,7 +340,7 @@
if (!mWakeLockHeld) {
if (mWakeLock != null) {
mWakeLockHeld = true;
- mWakeLock.acquire();
+ mWakeLock.acquire(TAG);
} else {
Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
}
@@ -654,7 +654,7 @@
private void onFinished(Callback callback) {
if (mWakeLockHeld) {
- mWakeLock.release();
+ mWakeLock.release(TAG);
mWakeLockHeld = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index b835909..7991e38 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,30 +23,34 @@
*/
public class DelayedWakeLock implements WakeLock {
+ private static final String TO_STRING_PREFIX = "[DelayedWakeLock] ";
private static final long RELEASE_DELAY_MS = 100;
private final Handler mHandler;
private final WakeLock mInner;
- private final Runnable mRelease;
public DelayedWakeLock(Handler h, WakeLock inner) {
mHandler = h;
mInner = inner;
- mRelease = mInner::release;
}
@Override
- public void acquire() {
- mInner.acquire();
+ public void acquire(String why) {
+ mInner.acquire(why);
}
@Override
- public void release() {
- mHandler.postDelayed(mRelease, RELEASE_DELAY_MS);
+ public void release(String why) {
+ mHandler.postDelayed(() -> mInner.release(why), RELEASE_DELAY_MS);
}
@Override
public Runnable wrap(Runnable r) {
return WakeLock.wrapImpl(this, r);
}
+
+ @Override
+ public String toString() {
+ return TO_STRING_PREFIX + mInner;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
index a54b0e1..283be86 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
@@ -26,6 +26,7 @@
public class KeepAwakeAnimationListener extends AnimatorListenerAdapter
implements Animation.AnimationListener {
+ private static final String TAG = "KeepAwakeAnimListener";
@VisibleForTesting
static WakeLock sWakeLock;
@@ -63,11 +64,11 @@
private void onStart() {
Assert.isMainThread();
- sWakeLock.acquire();
+ sWakeLock.acquire(TAG);
}
private void onEnd() {
Assert.isMainThread();
- sWakeLock.release();
+ sWakeLock.release(TAG);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
index 13729df..a797287 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
@@ -21,13 +21,15 @@
public class SettableWakeLock {
private final WakeLock mInner;
+ private final String mWhy;
private boolean mAcquired;
- public SettableWakeLock(WakeLock inner) {
+ public SettableWakeLock(WakeLock inner, String why) {
Preconditions.checkNotNull(inner, "inner wakelock required");
mInner = inner;
+ mWhy = why;
}
public synchronized boolean isAcquired() {
@@ -37,9 +39,9 @@
public synchronized void setAcquired(boolean acquired) {
if (mAcquired != acquired) {
if (acquired) {
- mInner.acquire();
+ mInner.acquire(mWhy);
} else {
- mInner.release();
+ mInner.release(mWhy);
}
mAcquired = acquired;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index b0f1b54..bebc20b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -18,17 +18,29 @@
import android.content.Context;
import android.os.PowerManager;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import java.util.HashMap;
+
/** WakeLock wrapper for testability */
public interface WakeLock {
- /** @see android.os.PowerManager.WakeLock#acquire() */
- void acquire();
+ static final String TAG = "WakeLock";
+ static final String REASON_WRAP = "wrap";
- /** @see android.os.PowerManager.WakeLock#release() */
- void release();
+ /**
+ * @param why A tag that will be saved for sysui dumps.
+ * @see android.os.PowerManager.WakeLock#acquire()
+ **/
+ void acquire(String why);
+
+ /**
+ * @param why Same tag used in {@link #acquire(String)}
+ * @see android.os.PowerManager.WakeLock#release()
+ **/
+ void release(String why);
/** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
Runnable wrap(Runnable r);
@@ -44,25 +56,38 @@
}
static Runnable wrapImpl(WakeLock w, Runnable r) {
- w.acquire();
+ w.acquire(REASON_WRAP);
return () -> {
try {
r.run();
} finally {
- w.release();
+ w.release(REASON_WRAP);
}
};
}
static WakeLock wrap(final PowerManager.WakeLock inner) {
return new WakeLock() {
+ private final HashMap<String, Integer> mActiveClients = new HashMap<>();
+
/** @see PowerManager.WakeLock#acquire() */
- public void acquire() {
+ public void acquire(String why) {
+ mActiveClients.putIfAbsent(why, 0);
+ mActiveClients.put(why, mActiveClients.get(why) + 1);
inner.acquire();
}
/** @see PowerManager.WakeLock#release() */
- public void release() {
+ public void release(String why) {
+ Integer count = mActiveClients.get(why);
+ if (count == null) {
+ Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
+ new Throwable());
+ } else if (count == 1) {
+ mActiveClients.remove(why);
+ } else {
+ mActiveClients.put(why, count - 1);
+ }
inner.release();
}
@@ -70,6 +95,11 @@
public Runnable wrap(Runnable runnable) {
return wrapImpl(this, runnable);
}
+
+ @Override
+ public String toString() {
+ return "active clients= " + mActiveClients.toString();
+ }
};
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 01d7b8b..e1717be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -166,25 +166,22 @@
@Test
public void onMetadataChanged_updatesSlice() {
- mProvider.onMetadataChanged(mock(MediaMetadata.class));
mProvider.onDozingChanged(true);
+ reset(mContentResolver);
+ mProvider.onMetadataChanged(mock(MediaMetadata.class));
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
// Hides after waking up
reset(mContentResolver);
mProvider.onDozingChanged(false);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
-
- // And won't update slice if device is awake
- reset(mContentResolver);
- mProvider.onMetadataChanged(mock(MediaMetadata.class));
- verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
}
@Test
public void onDozingChanged_updatesSliceIfMedia() {
- // Show media when dozing
mProvider.onMetadataChanged(mock(MediaMetadata.class));
+ reset(mContentResolver);
+ // Show media when dozing
mProvider.onDozingChanged(true);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
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 c20d37f..e4da859 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
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -441,10 +442,10 @@
@Test
public void testHoldsWakeLock_whenAOD() {
mScrimController.transitionTo(ScrimState.AOD);
- verify(mWakeLock).acquire();
- verify(mWakeLock, never()).release();
+ verify(mWakeLock).acquire(anyString());
+ verify(mWakeLock, never()).release(anyString());
mScrimController.finishAnimationsImmediately();
- verify(mWakeLock).release();
+ verify(mWakeLock).release(anyString());
}
@Test
@@ -471,10 +472,10 @@
reset(mWakeLock);
mScrimController.onHideWallpaperTimeout();
- verify(mWakeLock).acquire();
- verify(mWakeLock, never()).release();
+ verify(mWakeLock).acquire(anyString());
+ verify(mWakeLock, never()).release(anyString());
mScrimController.finishAnimationsImmediately();
- verify(mWakeLock).release();
+ verify(mWakeLock).release(anyString());
}
@Test
@@ -486,10 +487,10 @@
reset(mWakeLock);
mScrimController.onHideWallpaperTimeout();
- verify(mWakeLock).acquire();
- verify(mWakeLock, never()).release();
+ verify(mWakeLock).acquire(anyString());
+ verify(mWakeLock, never()).release(anyString());
mScrimController.finishAnimationsImmediately();
- verify(mWakeLock).release();
+ verify(mWakeLock).release(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
index ab9b0c9..0792a05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.util.wakelock;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -52,11 +53,11 @@
@Test
public void onAnimationStart_holdsWakeLock() {
mKeepAwakeAnimationListener.onAnimationStart((Animator) null);
- verify(mWakeLock).acquire();
- verify(mWakeLock, never()).release();
+ verify(mWakeLock).acquire(anyString());
+ verify(mWakeLock, never()).release(anyString());
mKeepAwakeAnimationListener.onAnimationEnd((Animator) null);
- verify(mWakeLock).release();
+ verify(mWakeLock).release(anyString());
}
@Test(expected = IllegalStateException.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
index 39316ed..f739fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
@@ -40,7 +40,7 @@
@Before
public void setup() {
mFake = new WakeLockFake();
- mSettable = new SettableWakeLock(mFake);
+ mSettable = new SettableWakeLock(mFake, "Fake");
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
index 4cefb99..ef20df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
@@ -23,24 +23,24 @@
private int mAcquired = 0;
@Override
- public void acquire() {
+ public void acquire(String why) {
mAcquired++;
}
@Override
- public void release() {
+ public void release(String why) {
Preconditions.checkState(mAcquired > 0);
mAcquired--;
}
@Override
public Runnable wrap(Runnable runnable) {
- acquire();
+ acquire(WakeLockFake.class.getSimpleName());
return () -> {
try {
runnable.run();
} finally {
- release();
+ release(WakeLockFake.class.getSimpleName());
}
};
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index d925364..4425def 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -19,9 +19,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.content.Context;
import android.os.PowerManager;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -36,6 +34,7 @@
@RunWith(AndroidJUnit4.class)
public class WakeLockTest extends SysuiTestCase {
+ private static final String WHY = "test";
WakeLock mWakeLock;
PowerManager.WakeLock mInner;
@@ -58,22 +57,22 @@
@Test
public void wakeLock_acquire() {
- mWakeLock.acquire();
+ mWakeLock.acquire(WHY);
assertTrue(mInner.isHeld());
}
@Test
public void wakeLock_release() {
- mWakeLock.acquire();
- mWakeLock.release();
+ mWakeLock.acquire(WHY);
+ mWakeLock.release(WHY);
assertFalse(mInner.isHeld());
}
@Test
public void wakeLock_refCounted() {
- mWakeLock.acquire();
- mWakeLock.acquire();
- mWakeLock.release();
+ mWakeLock.acquire(WHY);
+ mWakeLock.acquire(WHY);
+ mWakeLock.release(WHY);
assertTrue(mInner.isHeld());
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 4a3f126..e0fb337 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -1026,6 +1026,29 @@
}
@Override
+ public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
+ @Nullable List<ComponentName> activities, @NonNull IResultReceiver receiver)
+ throws RemoteException {
+ final int userId = UserHandle.getCallingUserId();
+
+ boolean ok;
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ ok = service.setAugmentedAutofillWhitelistLocked(packages, activities,
+ getCallingUid());
+ } else {
+ if (sVerbose) {
+ Slog.v(TAG, "setAugmentedAutofillWhitelist(): no service for " + userId);
+ }
+ ok = false;
+ }
+ }
+ send(receiver,
+ ok ? AutofillManager.RESULT_OK : AutofillManager.RESULT_CODE_NOT_SERVICE);
+ }
+
+ @Override
public void getAvailableFieldClassificationAlgorithms(@NonNull IResultReceiver receiver)
throws RemoteException {
final int userId = UserHandle.getCallingUserId();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1bce11ee..15dce4a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -40,6 +40,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -58,6 +59,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.LocalLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -165,6 +167,16 @@
@Nullable
private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
+ @GuardedBy("mLock")
+ @Nullable
+ private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
+
+ /**
+ * List of packages that are whitelisted to be trigger augmented autofill.
+ */
+ @GuardedBy("mLock")
+ private final ArraySet<String> mWhitelistedAugmentAutofillPackages = new ArraySet<>();
+
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
AutofillCompatState autofillCompatState,
@@ -844,10 +856,11 @@
}
@GuardedBy("mLock")
- private boolean isCalledByServiceLocked(String methodName, int callingUid) {
- if (getServiceUidLocked() != callingUid) {
+ private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) {
+ final int serviceUid = getServiceUidLocked();
+ if (serviceUid != callingUid) {
Slog.w(TAG, methodName + "() called by UID " + callingUid
- + ", but service UID is " + getServiceUidLocked());
+ + ", but service UID is " + serviceUid);
return false;
}
return true;
@@ -886,6 +899,19 @@
pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
mRemoteAugmentedAutofillService.dump(prefix2, pw);
}
+ if (mRemoteAugmentedAutofillServiceInfo != null) {
+ pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: ");
+ pw.println(mRemoteAugmentedAutofillServiceInfo);
+ }
+
+ final int whitelistSize = mWhitelistedAugmentAutofillPackages.size();
+ pw.print(prefix); pw.print("Packages whitelisted for augmented autofill: ");
+ pw.println(whitelistSize);
+ for (int i = 0; i < whitelistSize; i++) {
+ final String whitelistedPkg = mWhitelistedAugmentAutofillPackages.valueAt(i);
+ pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
+ }
+
pw.print(prefix); pw.print("Field classification enabled: ");
pw.println(isFieldClassificationEnabledLocked());
pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1037,9 +1063,13 @@
}
return null;
}
- final ComponentName componentName = RemoteAugmentedAutofillService.getComponentName(
- serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
- if (componentName == null) return null;
+ final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
+ .getComponentName(
+ serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
+ if (pair == null) return null;
+
+ mRemoteAugmentedAutofillServiceInfo = pair.first;
+ final ComponentName componentName = pair.second;
if (sVerbose) {
Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
}
@@ -1067,13 +1097,92 @@
private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
if (serviceName == null) {
if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): time's up!");
- if (mRemoteAugmentedAutofillService != null) {
- mRemoteAugmentedAutofillService.destroy();
- mRemoteAugmentedAutofillService = null;
+ synchronized (mLock) {
+ if (mRemoteAugmentedAutofillService != null) {
+ mRemoteAugmentedAutofillService.destroy();
+ mRemoteAugmentedAutofillService = null;
+ }
}
}
}
+ /**
+ * Sets which packages and activities can trigger augmented autofill.
+ *
+ * @return whether caller UID is the augmented autofill service for the user
+ */
+ boolean setAugmentedAutofillWhitelistLocked(List<String> packages,
+ List<ComponentName> activities, int callingUid) {
+
+ if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
+ callingUid)) {
+ return false;
+ }
+ if (mMaster.verbose) {
+ Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
+ + activities + ")");
+ }
+ whitelistForAugmentedAutofillPackages(packages);
+
+ // TODO(b/123100824): whitelist activities as well
+ // TODO(b/122858578): log metrics
+ return true;
+ }
+
+ @GuardedBy("mLock")
+ private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName,
+ int callingUid) {
+ // Lazy load service first
+ final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked();
+ if (service == null) {
+ Slog.w(TAG, methodName + "() called by UID " + callingUid
+ + ", but there is no augmented autofill service defined for user "
+ + getUserId());
+ return false;
+ }
+
+ if (getAugmentedAutofillServiceUidLocked() != callingUid) {
+ Slog.w(TAG, methodName + "() called by UID " + callingUid
+ + ", but service UID is " + getAugmentedAutofillServiceUidLocked()
+ + " for user " + getUserId());
+ return false;
+ }
+ return true;
+ }
+
+ @GuardedBy("mLock")
+ private int getAugmentedAutofillServiceUidLocked() {
+ if (mRemoteAugmentedAutofillServiceInfo == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getAugmentedAutofillServiceUid(): "
+ + "no mRemoteAugmentedAutofillServiceInfo");
+ }
+ return Process.INVALID_UID;
+ }
+ return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
+ }
+
+ @GuardedBy("mLock")
+ boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
+ // TODO(b/122595322): need to check whitelisted activities as well.
+ final String packageName = componentName.getPackageName();
+ return mWhitelistedAugmentAutofillPackages.contains(packageName);
+ }
+
+ private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
+ // TODO(b/123100824): add CTS test for when it's null
+ synchronized (mLock) {
+ if (packages == null) {
+ if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted augmented packages");
+ mWhitelistedAugmentAutofillPackages.clear();
+ } else {
+ if (mMaster.verbose) Slog.v(TAG, "whitelisting augmented packages: " + packages);
+ mWhitelistedAugmentAutofillPackages.addAll(packages);
+ }
+ mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
+ }
+ }
+
private void sendStateToClients(boolean resetClient) {
final RemoteCallbackList<IAutoFillManagerClient> clients;
final int userClientCount;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 61f63d3..88228fb 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -32,6 +32,7 @@
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
import android.text.format.DateUtils;
+import android.util.Pair;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -54,10 +55,13 @@
boolean bindInstantServiceAllowed, boolean verbose) {
super(context, AugmentedAutofillService.SERVICE_INTERFACE, serviceName, userId, callbacks,
bindInstantServiceAllowed, verbose);
+
+ // Bind right away.
+ scheduleBind();
}
@Nullable
- public static ComponentName getComponentName(@NonNull String componentName,
+ static Pair<ServiceInfo, ComponentName> getComponentName(@NonNull String componentName,
@UserIdInt int userId, boolean isTemporary) {
int flags = PackageManager.GET_META_DATA;
if (!isTemporary) {
@@ -78,7 +82,23 @@
Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
return null;
}
- return serviceComponent;
+ return new Pair<>(serviceInfo, serviceComponent);
+ }
+
+ @Override // from RemoteService
+ protected void handleOnConnectedStateChanged(boolean state) {
+ if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
+ scheduleUnbind();
+ }
+ try {
+ if (state) {
+ mService.onConnected();
+ } else {
+ mService.onDisconnected();
+ }
+ } catch (Exception e) {
+ Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
+ }
}
@Override // from AbstractRemoteService
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 04fc258..848f249 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2613,13 +2613,25 @@
+ " when server returned null for session " + this.id);
}
+ final boolean isWhitelisted = mService
+ .isWhitelistedForAugmentedAutofillLocked(mComponentName);
+
final String historyItem =
"aug:id=" + id + " u=" + uid + " m=" + mode
+ " a=" + ComponentName.flattenToShortString(mComponentName)
+ " f=" + mCurrentViewId
- + " s=" + remoteService.getComponentName();
+ + " s=" + remoteService.getComponentName()
+ + " w=" + isWhitelisted;
mService.getMaster().logRequestLocked(historyItem);
+ if (!isWhitelisted) {
+ if (sVerbose) {
+ Slog.v(TAG, mComponentName.toShortString() + " is not whitelisted for "
+ + "augmented autofill");
+ }
+ return null;
+ }
+
final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
// TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bfe1f6a..96cd79b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5615,7 +5615,7 @@
int checkCallingPermission(String permission) {
return checkPermission(permission,
Binder.getCallingPid(),
- UserHandle.getAppId(Binder.getCallingUid()));
+ Binder.getCallingUid());
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b1c186e..9ff2f44 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15835,6 +15835,12 @@
if (reconciledPkg.prepareResult.replace) {
PackageParser.Package oldPackage = mPackages.get(packageName);
+
+ // Set the update and install times
+ PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+ setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+ System.currentTimeMillis());
+
if (reconciledPkg.prepareResult.system) {
// Remove existing system package
removePackageLI(oldPackage, true);
@@ -15850,11 +15856,6 @@
res.removedInfo.args = null;
}
- // Set the update and install times
- PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
- setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
- System.currentTimeMillis());
-
// Update the package dynamic state if succeeded
// Now that the install succeeded make sure we remove data
// directories for any child package the update removed.
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index dacc6cd..6369179 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -642,10 +642,16 @@
// Location
if (locationPackageNames != null) {
for (String packageName : locationPackageNames) {
+ // STOPSHIP: remove this force-granting of legacy storage
+ // permissions once b/124466734 is resolved
+ final Set<String> storageWorkaround = new ArraySet<>();
+ storageWorkaround.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ storageWorkaround.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
grantPermissionsToSystemPackage(packageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
- SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
+ SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, storageWorkaround);
grantSystemFixedPermissionsToSystemPackage(packageName, userId,
LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 538813e..9ea819e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -938,7 +938,7 @@
return false;
}
// don't abort if the callingUid is in the foreground or is a persistent system process
- final int callingUidProcState = mService.getUidStateLocked(callingUid);
+ final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow =
mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
@@ -951,7 +951,7 @@
// take realCallingUid into consideration
final int realCallingUidProcState = (callingUid == realCallingUid)
? callingUidProcState
- : mService.getUidStateLocked(realCallingUid);
+ : mService.getUidState(realCallingUid);
final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
? callingUidHasAnyVisibleWindow
: mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(realCallingUid);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9b35e85..f24d680 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -26,7 +26,6 @@
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.STOP_APP_SWITCHES;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
@@ -272,6 +271,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -363,7 +366,7 @@
private UserManagerService mUserManager;
private AppOpsService mAppOpsService;
/** All active uids in the system. */
- private final SparseArray<Integer> mActiveUids = new SparseArray<>();
+ private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
/** All processes currently running that might have a window organized by name. */
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
@@ -647,6 +650,17 @@
}
}
+ /** Indicates that the method may be invoked frequently or is sensitive to performance. */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HotPath {
+ int NONE = 0;
+ int OOM_ADJUSTMENT = 1;
+ int LRU_UPDATE = 2;
+ int PROCESS_CHANGE = 3;
+ int caller() default NONE;
+ }
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public ActivityTaskManagerService(Context context) {
mContext = context;
@@ -5720,12 +5734,12 @@
return null;
}
- int getUidStateLocked(int uid) {
- return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
+ int getUidState(int uid) {
+ return mActiveUids.getUidState(uid);
}
boolean isUidForeground(int uid) {
- return (getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+ return (getUidState(uid) == ActivityManager.PROCESS_STATE_TOP)
|| mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
}
@@ -6118,23 +6132,26 @@
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void onProcessAdded(WindowProcessController proc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
mProcessNames.put(proc.mName, proc.mUid, proc);
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void onProcessRemoved(String name, int uid) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
mProcessNames.remove(name, uid);
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void onCleanUpApplicationRecord(WindowProcessController proc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
if (proc == mHomeProcess) {
mHomeProcess = null;
}
@@ -6144,23 +6161,26 @@
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public int getTopProcessState() {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
return mTopProcessState;
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public boolean isHeavyWeightProcess(WindowProcessController proc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
return proc == mHeavyWeightProcess;
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(proc);
}
}
@@ -6176,9 +6196,10 @@
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public boolean isSleeping() {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
return isSleepingLocked();
}
}
@@ -6422,9 +6443,10 @@
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public boolean isFactoryTestProcess(WindowProcessController wpc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
if (mFactoryTest == FACTORY_TEST_OFF) {
return false;
}
@@ -6477,10 +6499,11 @@
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void handleAppDied(WindowProcessController wpc, boolean restarting,
Runnable finishInstrumentationCallback) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
// Remove this application's activities from active lists.
boolean hasVisibleActivities = mRootActivityContainer.handleAppDied(wpc);
@@ -6579,16 +6602,18 @@
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public void preBindApplication(WindowProcessController wpc) {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(wpc.mInfo);
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
- synchronized (mGlobalLock) {
+ synchronized (mGlobalLockWithoutBoost) {
return mRootActivityContainer.attachApplication(wpc);
}
}
@@ -6916,6 +6941,7 @@
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public WindowProcessController getTopApp() {
synchronized (mGlobalLockWithoutBoost) {
@@ -6924,6 +6950,7 @@
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public void rankTaskLayersIfNeeded() {
synchronized (mGlobalLockWithoutBoost) {
@@ -6968,34 +6995,28 @@
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public void onUidActive(int uid, int procState) {
- synchronized (mGlobalLockWithoutBoost) {
- mActiveUids.put(uid, procState);
- }
+ mActiveUids.onUidActive(uid, procState);
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public void onUidInactive(int uid) {
- synchronized (mGlobalLockWithoutBoost) {
- mActiveUids.remove(uid);
- }
+ mActiveUids.onUidInactive(uid);
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public void onActiveUidsCleared() {
- synchronized (mGlobalLockWithoutBoost) {
- mActiveUids.clear();
- }
+ mActiveUids.onActiveUidsCleared();
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public void onUidProcStateChanged(int uid, int procState) {
- synchronized (mGlobalLockWithoutBoost) {
- if (mActiveUids.get(uid) != null) {
- mActiveUids.put(uid, procState);
- }
- }
+ mActiveUids.onUidProcStateChanged(uid, procState);
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e65973a..a19721f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -37,7 +37,6 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.View.GONE;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_TOP;
@@ -174,7 +173,6 @@
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -3270,9 +3268,6 @@
}
private void updateImeParent() {
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE) {
- return;
- }
final SurfaceControl newParent = computeImeParent();
if (newParent != null) {
mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent);
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
new file mode 100644
index 0000000..0047942
--- /dev/null
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import android.util.SparseIntArray;
+
+/**
+ * This is a partial mirror of {@link @com.android.server.am.ActiveUids}. It is already thread
+ * safe so the heavy service lock is not needed when updating state from activity manager (oom
+ * adjustment) or getting state from window manager (background start check).
+ */
+class MirrorActiveUids {
+ private SparseIntArray mUidStates = new SparseIntArray();
+
+ synchronized void onUidActive(int uid, int procState) {
+ mUidStates.put(uid, procState);
+ }
+
+ synchronized void onUidInactive(int uid) {
+ mUidStates.delete(uid);
+ }
+
+ synchronized void onActiveUidsCleared() {
+ mUidStates.clear();
+ }
+
+ synchronized void onUidProcStateChanged(int uid, int procState) {
+ final int index = mUidStates.indexOfKey(uid);
+ if (index >= 0) {
+ mUidStates.setValueAt(index, procState);
+ }
+ }
+
+ synchronized int getUidState(int uid) {
+ return mUidStates.get(uid, PROCESS_STATE_NONEXISTENT);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b915199..fc95789 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -71,6 +71,7 @@
import android.view.DisplayInfo;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
@@ -787,6 +788,14 @@
return 0;
}
+ @Override
+ void getRelativeDisplayedPosition(Point outPos) {
+ super.getRelativeDisplayedPosition(outPos);
+ final int outset = getStackOutset();
+ outPos.x -= outset;
+ outPos.y -= outset;
+ }
+
private void updateSurfaceSize(SurfaceControl.Transaction transaction) {
if (mSurfaceControl == null) {
return;
@@ -807,6 +816,11 @@
mLastSurfaceSize.set(width, height);
}
+ @VisibleForTesting
+ Point getLastSurfaceSize() {
+ return mLastSurfaceSize;
+ }
+
@Override
void onDisplayChanged(DisplayContent dc) {
if (mDisplayContent != null && mDisplayContent != dc) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 465f413..dceed28 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -57,6 +57,7 @@
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
+import com.android.server.wm.ActivityTaskManagerService.HotPath;
import java.io.IOException;
import java.io.PrintWriter;
@@ -408,12 +409,14 @@
return null;
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
public void addPackage(String packageName) {
synchronized (mAtm.mGlobalLockWithoutBoost) {
mPkgList.add(packageName);
}
}
+ @HotPath(caller = HotPath.PROCESS_CHANGE)
public void clearPackageList() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
mPkgList.clear();
@@ -441,12 +444,14 @@
mActivities.clear();
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasActivities() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
return !mActivities.isEmpty();
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasVisibleActivities() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
for (int i = mActivities.size() - 1; i >= 0; --i) {
@@ -459,6 +464,7 @@
return false;
}
+ @HotPath(caller = HotPath.LRU_UPDATE)
public boolean hasActivitiesOrRecentTasks() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
return !mActivities.isEmpty() || !mRecentTasks.isEmpty();
@@ -670,6 +676,7 @@
void onOtherActivity();
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
synchronized (mAtm.mGlobalLockWithoutBoost) {
final int activitiesSize = mActivities.size();
@@ -903,6 +910,7 @@
mRecentTasks.remove(task);
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasRecentTasks() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
return !mRecentTasks.isEmpty();
@@ -966,18 +974,21 @@
return false;
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public void onTopProcChanged() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
mAtm.mVrController.onTopProcChangedLocked(this);
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean isHomeProcess() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
return this == mAtm.mHomeProcess;
}
}
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean isPreviousProcess() {
synchronized (mAtm.mGlobalLockWithoutBoost) {
return this == mAtm.mPreviousProcess;
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 8d9b3cf..fe4825c 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -23,12 +23,14 @@
import static org.testng.Assert.assertEquals;
import android.app.usage.EventList;
+import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.res.Configuration;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.AtomicFile;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +40,7 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
@@ -448,4 +451,45 @@
runBackupRestoreTest(0);
runBackupRestoreTest(99999);
}
+
+ /**
+ * Test the pruning in indexFilesLocked() that only allow up to 100 daily files, 50 weekly files
+ * , 12 monthly files, 10 yearly files.
+ */
+ @Test
+ public void testMaxFiles() throws IOException {
+ final File[] intervalDirs = new File[]{
+ new File(mTestDir, "daily"),
+ new File(mTestDir, "weekly"),
+ new File(mTestDir, "monthly"),
+ new File(mTestDir, "yearly"),
+ };
+ // Create 10 extra files under each interval dir.
+ final int extra = 10;
+ final int length = intervalDirs.length;
+ for (int i = 0; i < length; i++) {
+ final int numFiles = UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra;
+ for (int f = 0; f < numFiles; f++) {
+ final AtomicFile file = new AtomicFile(new File(intervalDirs[i], Long.toString(f)));
+ FileOutputStream fos = file.startWrite();
+ fos.write(1);
+ file.finishWrite(fos);
+ }
+ }
+ // indexFilesLocked() list files under each interval dir, if number of files are more than
+ // the max allowed files for each interval type, it deletes the lowest numbered files.
+ mUsageStatsDatabase.forceIndexFiles();
+ final int len = mUsageStatsDatabase.mSortedStatFiles.length;
+ for (int i = 0; i < len; i++) {
+ final TimeSparseArray<AtomicFile> files = mUsageStatsDatabase.mSortedStatFiles[i];
+ // The stats file for each interval type equals to max allowed.
+ assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i],
+ files.size());
+ // The highest numbered file,
+ assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra - 1,
+ files.keyAt(files.size() - 1));
+ // The lowest numbered file:
+ assertEquals(extra, files.keyAt(0));
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 392b010..606ab31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -661,8 +661,8 @@
doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(realCallingUid);
// process importance
- doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
- doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
+ doReturn(callingUidProcState).when(mService).getUidState(callingUid);
+ doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
// foreground activities
final IApplicationThread caller = mock(IApplicationThread.class);
final ApplicationInfo ai = new ApplicationInfo();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 2554237..b1f942e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -19,6 +19,9 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
@@ -168,4 +171,22 @@
assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
assertTrue(task1.mOnDisplayChangedCalled);
}
+
+ @Test
+ public void testStackOutset() {
+ final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+ spyOn(stack);
+
+ final int stackOutset = 10;
+ doReturn(stackOutset).when(stack).getStackOutset();
+
+ final Rect stackBounds = new Rect(200, 200, 800, 1000);
+ // Update surface position and size by the given bounds.
+ stack.setBounds(stackBounds);
+
+ assertEquals(stackBounds.width() + 2 * stackOutset, stack.getLastSurfaceSize().x);
+ assertEquals(stackBounds.height() + 2 * stackOutset, stack.getLastSurfaceSize().y);
+ assertEquals(stackBounds.left - stackOutset, stack.getLastSurfacePosition().x);
+ assertEquals(stackBounds.top - stackOutset, stack.getLastSurfacePosition().y);
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 0e15947..dff6809 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -43,8 +43,8 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
@@ -84,6 +84,9 @@
@VisibleForTesting
public static final int BACKUP_VERSION = 4;
+ @VisibleForTesting
+ static final int[] MAX_FILES_PER_INTERVAL_TYPE = new int[]{100, 50, 12, 10};
+
// Key under which the payload blob is stored
// same as UsageStatsBackupHelper.KEY_USAGE_STATS
static final String KEY_USAGE_STATS = "usage_stats";
@@ -104,7 +107,8 @@
private final Object mLock = new Object();
private final File[] mIntervalDirs;
- private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
+ @VisibleForTesting
+ final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
private final UnixCalendar mCal;
private final File mVersionFile;
private final File mBackupsDir;
@@ -126,10 +130,10 @@
@VisibleForTesting
public UsageStatsDatabase(File dir, int version) {
mIntervalDirs = new File[]{
- new File(dir, "daily"),
- new File(dir, "weekly"),
- new File(dir, "monthly"),
- new File(dir, "yearly"),
+ new File(dir, "daily"),
+ new File(dir, "weekly"),
+ new File(dir, "monthly"),
+ new File(dir, "yearly"),
};
mCurrentVersion = version;
mVersionFile = new File(dir, "version");
@@ -248,6 +252,14 @@
return true;
}
+ /** @hide */
+ @VisibleForTesting
+ void forceIndexFiles() {
+ synchronized (mLock) {
+ indexFilesLocked();
+ }
+ }
+
private void indexFilesLocked() {
final FilenameFilter backupFileFilter = new FilenameFilter() {
@Override
@@ -255,7 +267,6 @@
return !name.endsWith(BAK_SUFFIX);
}
};
-
// Index the available usage stat files on disk.
for (int i = 0; i < mSortedStatFiles.length; i++) {
if (mSortedStatFiles[i] == null) {
@@ -268,8 +279,9 @@
if (DEBUG) {
Slog.d(TAG, "Found " + files.length + " stat files for interval " + i);
}
-
- for (File f : files) {
+ final int len = files.length;
+ for (int j = 0; j < len; j++) {
+ final File f = files[j];
final AtomicFile af = new AtomicFile(f);
try {
mSortedStatFiles[i].put(parseBeginTime(af), af);
@@ -277,6 +289,16 @@
Slog.e(TAG, "failed to index file: " + f, e);
}
}
+
+ // only keep the max allowed number of files for each interval type.
+ final int toDelete = mSortedStatFiles[i].size() - MAX_FILES_PER_INTERVAL_TYPE[i];
+ if (toDelete > 0) {
+ for (int j = 0; j < toDelete; j++) {
+ mSortedStatFiles[i].valueAt(0).delete();
+ mSortedStatFiles[i].removeAt(0);
+ }
+ Slog.d(TAG, "Deleted " + toDelete + " stat files for interval " + i);
+ }
}
}
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 3cb2216..ebd8e36 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -595,8 +595,8 @@
private void loadActiveStats(final long currentTimeMillis) {
for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
- if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
- currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
+ if (stats != null
+ && currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
if (DEBUG) {
Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 2462bee..fecdb08 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2186,7 +2186,10 @@
/**
* The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
- * content provider
+ * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
+ * performing an insert, ensure that the provided content values contain the other
+ * participant's ID under the key
+ * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
*/
Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
RCS_1_TO_1_THREAD_URI_PART);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1b7228a..ad98e36 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2481,6 +2481,17 @@
"opportunistic_network_data_switch_hysteresis_time_long";
/**
+ * Indicates zero or more emergency number prefix(es), because some carrier requires
+ * if users dial an emergency number address with a specific prefix, the combination of the
+ * prefix and the address is also a valid emergency number to dial. For example, an emergency
+ * number prefix is 318, and the emergency number is 911. Both 318911 and 911 can be dialed by
+ * users for emergency call. An empty array of string indicates that current carrier does not
+ * have this requirement.
+ */
+ public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY =
+ "emergency_number_prefix_string_array";
+
+ /**
* GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
* @hide
*/
@@ -2989,6 +3000,7 @@
new int[] {
1 /* Roaming Indicator Off */
});
+ sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
}
/**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 6958d22..7655834 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import java.util.Objects;
+import java.util.UUID;
/**
* CellIdentity represents the identity of a unique cell. This is the base class for
@@ -83,6 +84,13 @@
mMncStr = null;
log("invalid MNC format: " + mnc);
}
+
+ if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
+ DebugEventReporter.sendEvent(
+ UUID.fromString("a3ab0b9d-f2aa-4baf-911d-7096c0d4645a"),
+ "CellIdentity Missing Half of PLMN ID");
+ }
+
mAlphaLong = alphal;
mAlphaShort = alphas;
}