Merge "Move the logic of (re)evaluation of Private DNS" into pi-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 962cbbf..4260e40 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3083,10 +3083,10 @@
}
public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
- method public void addAddress(android.net.LinkAddress) throws java.io.IOException;
+ method public void addAddress(java.net.InetAddress, int) throws java.io.IOException;
method public void close();
method public java.lang.String getInterfaceName();
- method public void removeAddress(android.net.LinkAddress) throws java.io.IOException;
+ method public void removeAddress(java.net.InetAddress, int) throws java.io.IOException;
}
public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -5108,6 +5108,7 @@
}
public abstract class NetworkService extends android.app.Service {
+ ctor public NetworkService();
method protected abstract android.telephony.NetworkService.NetworkServiceProvider createNetworkServiceProvider(int);
field public static final java.lang.String NETWORK_SERVICE_EXTRA_SLOT_ID = "android.telephony.extra.SLOT_ID";
field public static final java.lang.String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
@@ -5389,6 +5390,7 @@
}
public abstract class DataService extends android.app.Service {
+ ctor public DataService();
method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int);
field public static final java.lang.String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index bc1c51a..8e46714 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -210,7 +210,8 @@
tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp \
tests/e2e/Anomaly_count_e2e_test.cpp \
tests/e2e/Anomaly_duration_sum_e2e_test.cpp \
- tests/e2e/ConfigTtl_e2e_test.cpp
+ tests/e2e/ConfigTtl_e2e_test.cpp \
+ tests/e2e/PartialBucket_e2e_test.cpp
LOCAL_STATIC_LIBRARIES := \
$(statsd_common_static_libraries) \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index de4ab63..90ce735 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -212,7 +212,10 @@
sp<MetricsManager> newMetricsManager =
new MetricsManager(key, config, mTimeBaseSec, (timestampNs - 1) / NS_PER_SEC + 1, mUidMap,
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
-
+ auto it = mMetricsManagers.find(key);
+ if (it != mMetricsManagers.end()) {
+ WriteDataToDiskLocked(it->first);
+ }
if (newMetricsManager->isConfigValid()) {
mUidMap->OnConfigUpdated(key);
if (newMetricsManager->shouldAddUidMapListener()) {
@@ -251,19 +254,10 @@
* onDumpReport dumps serialized ConfigMetricsReportList into outData.
*/
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
vector<uint8_t>* outData) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- auto it = mMetricsManagers.find(key);
- if (it == mMetricsManagers.end()) {
- ALOGW("Config source %s does not exist", key.ToString().c_str());
- return;
- }
-
- // This allows another broadcast to be sent within the rate-limit period if we get close to
- // filling the buffer again soon.
- mLastBroadcastTimes.erase(key);
-
ProtoOutputStream proto;
// Start of ConfigKey.
@@ -273,18 +267,26 @@
proto.end(configKeyToken);
// End of ConfigKey.
- // Start of ConfigMetricsReport (reports).
- uint64_t reportsToken =
- proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
- onConfigMetricsReportLocked(key, dumpTimeStampNs, &proto);
- proto.end(reportsToken);
- // End of ConfigMetricsReport (reports).
-
-
// Then, check stats-data directory to see there's any file containing
// ConfigMetricsReport from previous shutdowns to concatenate to reports.
StorageManager::appendConfigMetricsReport(key, &proto);
+ auto it = mMetricsManagers.find(key);
+ if (it != mMetricsManagers.end()) {
+ // This allows another broadcast to be sent within the rate-limit period if we get close to
+ // filling the buffer again soon.
+ mLastBroadcastTimes.erase(key);
+
+ // 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, &proto);
+ proto.end(reportsToken);
+ // End of ConfigMetricsReport (reports).
+ } else {
+ ALOGW("Config source %s does not exist", key.ToString().c_str());
+ }
+
if (outData != nullptr) {
outData->clear();
outData->resize(proto.size());
@@ -298,7 +300,7 @@
}
}
- StatsdStats::getInstance().noteMetricsReportSent(key);
+ StatsdStats::getInstance().noteMetricsReportSent(key, proto.size());
}
/*
@@ -306,20 +308,24 @@
*/
void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* proto) {
// We already checked whether key exists in mMetricsManagers in
// WriteDataToDisk.
auto it = mMetricsManagers.find(key);
+ if (it == mMetricsManagers.end()) {
+ return;
+ }
int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
- it->second->onDumpReport(dumpTimeStampNs, proto);
+ it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, proto);
// Fill in UidMap.
uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
- mUidMap->appendUidMap(key, proto);
+ mUidMap->appendUidMap(dumpTimeStampNs, key, proto);
proto->end(uidMapToken);
// Fill in the timestamps.
@@ -331,7 +337,6 @@
(long long)lastReportWallClockNs);
proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
(long long)getWallClockNs());
-
}
void StatsLogProcessor::resetIfConfigTtlExpiredLocked(const int64_t timestampNs) {
@@ -361,6 +366,7 @@
std::lock_guard<std::mutex> lock(mMetricsMutex);
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
+ WriteDataToDiskLocked(key);
mMetricsManagers.erase(it);
mUidMap->OnConfigRemoved(key);
}
@@ -406,22 +412,30 @@
}
}
+void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key) {
+ ProtoOutputStream proto;
+ onConfigMetricsReportLocked(key, getElapsedRealtimeNs(),
+ true /* include_current_partial_bucket*/, &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(),
+ O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ ALOGE("Attempt to write %s but failed", file_name.c_str());
+ return;
+ }
+ proto.flush(fd.get());
+}
+
+void StatsLogProcessor::WriteDataToDiskLocked() {
+ for (auto& pair : mMetricsManagers) {
+ WriteDataToDiskLocked(pair.first);
+ }
+}
+
void StatsLogProcessor::WriteDataToDisk() {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- for (auto& pair : mMetricsManagers) {
- const ConfigKey& key = pair.first;
- ProtoOutputStream proto;
- onConfigMetricsReportLocked(key, getElapsedRealtimeNs(), &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(),
- O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
- if (fd == -1) {
- VLOG("Attempt to write %s but failed", file_name.c_str());
- return;
- }
- proto.flush(fd.get());
- }
+ WriteDataToDiskLocked();
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index d37429e..1e82b1e 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -48,7 +48,8 @@
size_t GetMetricsSize(const ConfigKey& key) const;
- void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs, vector<uint8_t>* outData);
+ void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket, vector<uint8_t>* outData);
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
void onAnomalyAlarmFired(
@@ -102,7 +103,11 @@
void OnConfigUpdatedLocked(
const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);
+ void WriteDataToDiskLocked();
+ void WriteDataToDiskLocked(const ConfigKey& key);
+
void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
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 adc2664..f16109c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -501,7 +501,7 @@
if (good) {
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
- &data);
+ false /* include_current_bucket*/, &data);
// TODO: print the returned StatsLogReport to file instead of printing to logcat.
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
@@ -640,7 +640,7 @@
"Only system uid can call informAllUidData");
}
- mUidMap->updateMap(uid, version, app);
+ mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app);
VLOG("StatsService::informAllUidData succeeded");
return Status::ok();
@@ -653,7 +653,7 @@
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informOnePackage");
}
- mUidMap->updateApp(app, uid, version);
+ mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version);
return Status::ok();
}
@@ -664,7 +664,7 @@
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informOnePackageRemoved");
}
- mUidMap->removeApp(app, uid);
+ mUidMap->removeApp(getElapsedRealtimeNs(), app, uid);
mConfigManager->RemoveConfigs(uid);
return Status::ok();
}
@@ -800,7 +800,8 @@
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
if (checkCallingPermission(String16(kPermissionDump))) {
ConfigKey configKey(ipc->getCallingUid(), key);
- mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), output);
+ mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
+ false /* include_current_bucket*/, output);
return Status::ok();
} else {
return Status::fromExceptionCode(binder::Status::EX_SECURITY);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 8d2fd33..a4552e1 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -262,6 +262,10 @@
FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
+ FRIEND_TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp);
+ FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade);
+ FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval);
+ FRIEND_TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit);
};
} // namespace statsd
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index bdc8fa9..b589d0d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -76,7 +76,8 @@
const int FIELD_ID_CONFIG_STATS_VALID = 9;
const int FIELD_ID_CONFIG_STATS_BROADCAST = 10;
const int FIELD_ID_CONFIG_STATS_DATA_DROP = 11;
-const int FIELD_ID_CONFIG_STATS_DUMP_REPORT = 12;
+const int FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME = 12;
+const int FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES = 20;
const int FIELD_ID_CONFIG_STATS_MATCHER_STATS = 13;
const int FIELD_ID_CONFIG_STATS_CONDITION_STATS = 14;
const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15;
@@ -95,11 +96,10 @@
const int FIELD_ID_ALERT_STATS_ID = 1;
const int FIELD_ID_ALERT_STATS_COUNT = 2;
-const int FIELD_ID_UID_MAP_SNAPSHOTS = 1;
-const int FIELD_ID_UID_MAP_CHANGES = 2;
-const int FIELD_ID_UID_MAP_BYTES_USED = 3;
-const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
-const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
+const int FIELD_ID_UID_MAP_CHANGES = 1;
+const int FIELD_ID_UID_MAP_BYTES_USED = 2;
+const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 3;
+const int FIELD_ID_UID_MAP_DELETED_APPS = 4;
const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
{android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
@@ -216,32 +216,32 @@
it->second->data_drop_time_sec.push_back(timeSec);
}
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key) {
- noteMetricsReportSent(key, getWallClockSec());
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes) {
+ noteMetricsReportSent(key, num_bytes, getWallClockSec());
}
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) {
+void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes,
+ int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
auto it = mConfigStats.find(key);
if (it == mConfigStats.end()) {
ALOGE("Config key %s not found!", key.ToString().c_str());
return;
}
- if (it->second->dump_report_time_sec.size() == kMaxTimestampCount) {
- it->second->dump_report_time_sec.pop_front();
+ if (it->second->dump_report_stats.size() == kMaxTimestampCount) {
+ it->second->dump_report_stats.pop_front();
}
- it->second->dump_report_time_sec.push_back(timeSec);
+ it->second->dump_report_stats.push_back(std::make_pair(timeSec, num_bytes));
}
-void StatsdStats::noteUidMapDropped(int snapshots, int deltas) {
+void StatsdStats::noteUidMapDropped(int deltas) {
lock_guard<std::mutex> lock(mLock);
- mUidMapStats.dropped_snapshots += mUidMapStats.dropped_snapshots + snapshots;
mUidMapStats.dropped_changes += mUidMapStats.dropped_changes + deltas;
}
-void StatsdStats::setUidMapSnapshots(int snapshots) {
+void StatsdStats::noteUidMapAppDeletionDropped() {
lock_guard<std::mutex> lock(mLock);
- mUidMapStats.snapshots = snapshots;
+ mUidMapStats.deleted_apps++;
}
void StatsdStats::setUidMapChanges(int changes) {
@@ -385,7 +385,7 @@
for (auto& config : mConfigStats) {
config.second->broadcast_sent_time_sec.clear();
config.second->data_drop_time_sec.clear();
- config.second->dump_report_time_sec.clear();
+ config.second->dump_report_stats.clear();
config.second->annotations.clear();
config.second->matcher_stats.clear();
config.second->condition_stats.clear();
@@ -444,8 +444,8 @@
fprintf(out, "\tdata drop time: %d\n", dataDropTime);
}
- for (const auto& dumpTime : configStats->dump_report_time_sec) {
- fprintf(out, "\tdump report time: %d\n", dumpTime);
+ for (const auto& dump : configStats->dump_report_stats) {
+ fprintf(out, "\tdump report time: %d bytes: %lld\n", dump.first, (long long)dump.second);
}
for (const auto& stats : pair.second->matcher_stats) {
@@ -492,11 +492,9 @@
fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
}
- fprintf(out,
- "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
- "lost=%d\n",
- mUidMapStats.bytes_used, mUidMapStats.snapshots, mUidMapStats.changes,
- mUidMapStats.dropped_snapshots, mUidMapStats.dropped_changes);
+ fprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
+ mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps,
+ mUidMapStats.dropped_changes);
for (const auto& error : mLoggerErrors) {
time_t error_time = error.first;
@@ -540,9 +538,16 @@
drop);
}
- for (const auto& dump : configStats.dump_report_time_sec) {
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT | FIELD_COUNT_REPEATED,
- dump);
+ for (const auto& dump : configStats.dump_report_stats) {
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME |
+ FIELD_COUNT_REPEATED,
+ dump.first);
+ }
+
+ for (const auto& dump : configStats.dump_report_stats) {
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES |
+ FIELD_COUNT_REPEATED,
+ (long long)dump.second);
}
for (const auto& annotation : configStats.annotations) {
@@ -641,12 +646,10 @@
}
uint64_t uidMapToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_SNAPSHOTS, mUidMapStats.snapshots);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_CHANGES, mUidMapStats.changes);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_BYTES_USED, mUidMapStats.bytes_used);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS,
- mUidMapStats.dropped_snapshots);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DROPPED_CHANGES, mUidMapStats.dropped_changes);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DELETED_APPS, mUidMapStats.deleted_apps);
proto.end(uidMapToken);
for (const auto& error : mLoggerErrors) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 93f780c1..123a703 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -43,7 +43,7 @@
std::list<int32_t> broadcast_sent_time_sec;
std::list<int32_t> data_drop_time_sec;
- std::list<int32_t> dump_report_time_sec;
+ std::list<std::pair<int32_t, int64_t>> dump_report_stats;
// Stores how many times a matcher have been matched. The map size is capped by kMaxConfigCount.
std::map<const int64_t, int> matcher_stats;
@@ -73,11 +73,10 @@
};
struct UidMapStats {
- int32_t snapshots;
int32_t changes;
int32_t bytes_used;
- int32_t dropped_snapshots;
int32_t dropped_changes;
+ int32_t deleted_apps = 0;
};
// Keeps track of stats of statsd.
@@ -123,6 +122,9 @@
// is critical for understanding the metrics.
const static size_t kMaxBytesUsedUidMap = 50 * 1024;
+ // The number of deleted apps that are stored in the uid map.
+ const static int kMaxDeletedAppsInUidMap = 100;
+
/* Minimum period between two broadcasts in nanoseconds. */
static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
@@ -175,7 +177,7 @@
*
* The report may be requested via StatsManager API, or through adb cmd.
*/
- void noteMetricsReportSent(const ConfigKey& key);
+ void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes);
/**
* Report the size of output tuple of a condition.
@@ -246,14 +248,18 @@
void noteRegisteredPeriodicAlarmChanged();
/**
- * Records the number of snapshot and delta entries that are being dropped from the uid map.
+ * Records the number of delta entries that are being dropped from the uid map.
*/
- void noteUidMapDropped(int snapshots, int deltas);
+ void noteUidMapDropped(int deltas);
/**
- * Updates the number of snapshots currently stored in the uid map.
+ * Records that an app was deleted (from statsd's map).
*/
- void setUidMapSnapshots(int snapshots);
+ void noteUidMapAppDeletionDropped();
+
+ /**
+ * Updates the number of changes currently stored in the uid map.
+ */
void setUidMapChanges(int changes);
void setCurrentUidMapMemory(int bytes);
@@ -349,7 +355,7 @@
void noteDataDropped(const ConfigKey& key, int32_t timeSec);
- void noteMetricsReportSent(const ConfigKey& key, int32_t timeSec);
+ void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes, int32_t timeSec);
void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 98963bd..c77e07b 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -123,8 +123,13 @@
}
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* protoOutput) {
- flushIfNeededLocked(dumpTimeNs);
+ if (include_current_partial_bucket) {
+ flushLocked(dumpTimeNs);
+ } else {
+ flushIfNeededLocked(dumpTimeNs);
+ }
if (mPastBuckets.empty()) {
return;
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 5991c28..cafc882 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -54,7 +54,9 @@
const LogEvent& event) override;
private:
+
void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) override;
// Internal interface to handle condition change.
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 19155de..3125fa7 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -439,8 +439,13 @@
}
void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* protoOutput) {
- flushIfNeededLocked(dumpTimeNs);
+ if (include_current_partial_bucket) {
+ flushLocked(dumpTimeNs);
+ } else {
+ flushIfNeededLocked(dumpTimeNs);
+ }
if (mPastBuckets.empty()) {
VLOG(" Duration metric, empty return");
return;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 80fb829..80fbdde 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -62,6 +62,7 @@
bool condition, const LogEvent& event);
void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) override;
// Internal interface to handle condition change.
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index d55cb3f..33ab9aa 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -101,6 +101,7 @@
}
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* protoOutput) {
if (mProto->size() <= 0) {
return;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index fbbc7e2..5c29174 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -47,6 +47,7 @@
const LogEvent& event) override;
void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) override;
// Internal interface to handle condition change.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 2561d1d..3c77aae 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -156,8 +156,14 @@
}
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* protoOutput) {
VLOG("Gauge metric %lld report now...", (long long)mMetricId);
+ if (include_current_partial_bucket) {
+ flushLocked(dumpTimeNs);
+ } else {
+ flushIfNeededLocked(dumpTimeNs);
+ }
flushIfNeededLocked(dumpTimeNs);
if (mPastBuckets.empty()) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index f49180f..04b7df9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -88,6 +88,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) override;
// for testing
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 139a407..f931e57 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -80,11 +80,13 @@
};
void notifyAppRemoved(const int64_t& eventTimeNs, const string& apk, const int uid) override{
- // TODO: Implement me.
+ // Force buckets to split on removal also.
+ notifyAppUpgrade(eventTimeNs, apk, uid, 0);
};
void onUidMapReceived(const int64_t& eventTimeNs) override{
- // TODO: Implement me.
+ // Purposefully don't flush partial buckets on a new snapshot.
+ // This occurs if a new user is added/removed or statsd crashes.
};
// Consume the parsed stats log entry that already matched the "what" of the metric.
@@ -110,9 +112,11 @@
// Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
// This method clears all the past buckets.
- void onDumpReport(const int64_t dumpTimeNs, android::util::ProtoOutputStream* protoOutput) {
+ void onDumpReport(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
+ android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, protoOutput);
+ return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, protoOutput);
}
void dumpStates(FILE* out, bool verbose) const {
@@ -166,16 +170,26 @@
virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) = 0;
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) = 0;
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
/**
- * Flushes the current bucket if the eventTime is after the current bucket's end time.
+ * Flushes the current bucket if the eventTime is after the current bucket's end time. This will
+ also flush the current partial bucket in memory.
*/
virtual void flushIfNeededLocked(const int64_t& eventTime){};
/**
+ * Flushes all the data including the current partial bucket.
+ */
+ virtual void flushLocked(const int64_t& eventTime) {
+ flushIfNeededLocked(eventTime);
+ flushCurrentBucketLocked(eventTime);
+ };
+
+ /**
* For metrics that aggregate (ie, every metric producer except for EventMetricProducer),
* we need to be able to flush the current buckets on demand (ie, end the current bucket and
* start new bucket). If this function is called when eventTimeNs is greater than the current
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 22827b0..b7f1bd5 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -190,14 +190,16 @@
}
}
-void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, ProtoOutputStream* protoOutput) {
+void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
+ ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
// one StatsLogReport per MetricProduer
for (const auto& producer : mAllMetricProducers) {
if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
uint64_t token =
protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
- producer->onDumpReport(dumpTimeStampNs, protoOutput);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, protoOutput);
protoOutput->end(token);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 9a9b33c..6aa260a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -90,8 +90,8 @@
virtual void dropData(const int64_t dropTimeNs);
- // Config source owner can call onDumpReport() to get all the metrics collected.
virtual void onDumpReport(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput);
// Computes the total byte size of all metrics managed by a single config source.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index fd623ca..51fac8c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -147,9 +147,14 @@
}
void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
- flushIfNeededLocked(dumpTimeNs);
+ if (include_current_partial_bucket) {
+ flushLocked(dumpTimeNs);
+ } else {
+ flushIfNeededLocked(dumpTimeNs);
+ }
if (mPastBuckets.empty()) {
return;
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index c8f7062..b5f6429 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -87,6 +87,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket,
android::util::ProtoOutputStream* protoOutput) override;
// Internal interface to handle condition change.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index b7c5795..566d34e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -263,15 +263,14 @@
}
bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
- const unordered_map<int64_t, int>& logTrackerMap,
+ UidMap& uidMap, const unordered_map<int64_t, int>& logTrackerMap,
const unordered_map<int64_t, int>& conditionTrackerMap,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<int64_t, int>& metricMap,
- std::set<int64_t> &noReportMetricIds) {
+ unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
config.event_metric_size() + config.value_metric_size();
@@ -538,6 +537,9 @@
}
noReportMetricIds.insert(no_report_metric);
}
+ for (auto it : allMetricProducers) {
+ uidMap.addListener(it);
+ }
return true;
}
@@ -642,12 +644,10 @@
return true;
}
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
- const UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
- const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec, const long currentTimeSec,
- set<int>& allTagIds,
+ const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
+ const long currentTimeSec, set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
@@ -656,7 +656,7 @@
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::set<int64_t> &noReportMetricIds) {
+ std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
unordered_map<int64_t, int> conditionTrackerMap;
unordered_map<int64_t, int> metricProducerMap;
@@ -673,9 +673,10 @@
return false;
}
- if (!initMetrics(key, config, timeBaseSec, logTrackerMap, conditionTrackerMap, allAtomMatchers,
- allConditionTrackers, allMetricProducers, conditionToMetricMap,
- trackerToMetricMap, metricProducerMap, noReportMetricIds)) {
+ if (!initMetrics(key, config, timeBaseSec, uidMap, logTrackerMap, conditionTrackerMap,
+ allAtomMatchers, allConditionTrackers, allMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, metricProducerMap,
+ noReportMetricIds)) {
ALOGE("initMetricProducers failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 3754ae0..0ebdcf9 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -81,7 +81,7 @@
// the list of MetricProducer index
// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
bool initMetrics(
- const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
+ const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec, UidMap& uidMap,
const std::unordered_map<int64_t, int>& logTrackerMap,
const std::unordered_map<int64_t, int>& conditionTrackerMap,
const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
@@ -90,16 +90,14 @@
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
- std::set<int64_t> &noReportMetricIds);
+ std::set<int64_t>& noReportMetricIds);
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
- const UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
- const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec, const long currentTimeSec,
- std::set<int>& allTagIds,
+ const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
+ const long currentTimeSec, std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
@@ -108,7 +106,7 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::set<int64_t> &noReportMetricIds);
+ std::set<int64_t>& noReportMetricIds);
bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 8c8152d..b3425a4 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -45,6 +45,7 @@
const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1;
const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2;
const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3;
+const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4;
const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1;
const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2;
const int FIELD_ID_SNAPSHOTS = 1;
@@ -53,7 +54,8 @@
const int FIELD_ID_CHANGE_TIMESTAMP = 2;
const int FIELD_ID_CHANGE_PACKAGE = 3;
const int FIELD_ID_CHANGE_UID = 4;
-const int FIELD_ID_CHANGE_VERSION = 5;
+const int FIELD_ID_CHANGE_NEW_VERSION = 5;
+const int FIELD_ID_CHANGE_PREV_VERSION = 6;
UidMap::UidMap() : mBytesUsed(0) {}
@@ -62,13 +64,8 @@
bool UidMap::hasApp(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
- auto range = mMap.equal_range(uid);
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second.packageName == packageName) {
- return true;
- }
- }
- return false;
+ auto it = mMap.find(std::make_pair(uid, packageName));
+ return it != mMap.end() && !it->second.deleted;
}
string UidMap::normalizeAppName(const string& appName) const {
@@ -84,10 +81,10 @@
std::set<string> UidMap::getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const {
std::set<string> names;
- auto range = mMap.equal_range(uid);
- for (auto it = range.first; it != range.second; ++it) {
- names.insert(returnNormalized ?
- normalizeAppName(it->second.packageName) : it->second.packageName);
+ for (const auto& kv : mMap) {
+ if (kv.first.first == uid && !kv.second.deleted) {
+ names.insert(returnNormalized ? normalizeAppName(kv.first.second) : kv.first.second);
+ }
}
return names;
}
@@ -95,18 +92,11 @@
int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
- auto range = mMap.equal_range(uid);
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second.packageName == packageName) {
- return it->second.versionCode;
- }
+ auto it = mMap.find(std::make_pair(uid, packageName));
+ if (it == mMap.end() || it->second.deleted) {
+ return 0;
}
- return 0;
-}
-
-void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
- const vector<String16>& packageName) {
- updateMap(getElapsedRealtimeNs(), uid, versionCode, packageName);
+ return it->second.versionCode;
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
@@ -115,20 +105,31 @@
{
lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
- mMap.clear();
- vector<const SnapshotPackageInfo> infos;
- for (size_t j = 0; j < uid.size(); j++) {
- string package = string(String8(packageName[j]).string());
- mMap.insert(make_pair(uid[j], AppData(package, versionCode[j])));
- infos.emplace_back(package, versionCode[j], uid[j]);
+ std::unordered_map<std::pair<int, string>, AppData, PairHash> deletedApps;
+
+ // Copy all the deleted apps.
+ for (const auto& kv : mMap) {
+ if (kv.second.deleted) {
+ deletedApps[kv.first] = kv.second;
+ }
}
- mSnapshots.emplace_back(timestamp, infos);
+ mMap.clear();
+ for (size_t j = 0; j < uid.size(); j++) {
+ string package = string(String8(packageName[j]).string());
+ mMap[std::make_pair(uid[j], package)] = AppData(versionCode[j]);
+ }
- mBytesUsed += mSnapshots.back().bytes;
+ for (const auto& kv : deletedApps) {
+ auto mMapIt = mMap.find(kv.first);
+ if (mMapIt != mMap.end()) {
+ // Insert this deleted app back into the current map.
+ mMap[kv.first] = kv.second;
+ }
+ }
+
ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
- StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
getListenerListCopyLocked(&broadcastList);
}
// To avoid invoking callback while holding the internal lock. we get a copy of the listener
@@ -144,38 +145,34 @@
}
}
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
- updateApp(getElapsedRealtimeNs(), app_16, uid, versionCode);
-}
-
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
const int64_t& versionCode) {
vector<wp<PackageInfoListener>> broadcastList;
string appName = string(String8(app_16).string());
{
lock_guard<mutex> lock(mMutex);
-
- mChanges.emplace_back(false, timestamp, appName, uid, versionCode);
+ int32_t prevVersion = 0;
+ bool found = false;
+ auto it = mMap.find(std::make_pair(uid, appName));
+ if (it != mMap.end()) {
+ found = true;
+ prevVersion = it->second.versionCode;
+ it->second.versionCode = versionCode;
+ it->second.deleted = false;
+ }
+ if (!found) {
+ // Otherwise, we need to add an app at this uid.
+ mMap[std::make_pair(uid, appName)] = AppData(versionCode);
+ } else {
+ // Only notify the listeners if this is an app upgrade. If this app is being installed
+ // for the first time, then we don't notify the listeners.
+ getListenerListCopyLocked(&broadcastList);
+ }
+ mChanges.emplace_back(false, timestamp, appName, uid, versionCode, prevVersion);
mBytesUsed += kBytesChangeRecord;
ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-
- auto range = mMap.equal_range(int(uid));
- bool found = false;
- for (auto it = range.first; it != range.second; ++it) {
- // If we find the exact same app name and uid, update the app version directly.
- if (it->second.packageName == appName) {
- it->second.versionCode = versionCode;
- found = true;
- break;
- }
- }
- if (!found) {
- // Otherwise, we need to add an app at this uid.
- mMap.insert(make_pair(uid, AppData(appName, versionCode)));
- }
- getListenerListCopyLocked(&broadcastList);
}
for (auto weakPtr : broadcastList) {
@@ -195,22 +192,14 @@
}
while (mBytesUsed > limit) {
ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
- if (mSnapshots.size() > 0) {
- mBytesUsed -= mSnapshots.front().bytes;
- mSnapshots.pop_front();
- StatsdStats::getInstance().noteUidMapDropped(1, 0);
- } else if (mChanges.size() > 0) {
+ if (mChanges.size() > 0) {
mBytesUsed -= kBytesChangeRecord;
mChanges.pop_front();
- StatsdStats::getInstance().noteUidMapDropped(0, 1);
+ StatsdStats::getInstance().noteUidMapDropped(1);
}
}
}
-void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
- removeApp(getElapsedRealtimeNs(), app_16, uid);
-}
-
void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) {
for (auto weakIt = mSubscribers.begin(); weakIt != mSubscribers.end();) {
auto strongPtr = weakIt->promote();
@@ -230,19 +219,26 @@
{
lock_guard<mutex> lock(mMutex);
- mChanges.emplace_back(true, timestamp, app, uid, 0);
+ int32_t prevVersion = 0;
+ auto key = std::make_pair(uid, app);
+ auto it = mMap.find(key);
+ if (it != mMap.end() && !it->second.deleted) {
+ prevVersion = it->second.versionCode;
+ it->second.deleted = true;
+ mDeletedApps.push_back(key);
+ }
+ if (mDeletedApps.size() > StatsdStats::kMaxDeletedAppsInUidMap) {
+ // Delete the oldest one.
+ auto oldest = mDeletedApps.front();
+ mDeletedApps.pop_front();
+ mMap.erase(oldest);
+ StatsdStats::getInstance().noteUidMapAppDeletionDropped();
+ }
+ mChanges.emplace_back(true, timestamp, app, uid, 0, prevVersion);
mBytesUsed += kBytesChangeRecord;
ensureBytesUsedBelowLimit();
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-
- auto range = mMap.equal_range(int(uid));
- for (auto it = range.first; it != range.second; ++it) {
- if (it->second.packageName == app) {
- mMap.erase(it);
- break;
- }
- }
getListenerListCopyLocked(&broadcastList);
}
@@ -290,22 +286,20 @@
}
void UidMap::clearOutput() {
- mSnapshots.clear();
mChanges.clear();
// Also update the guardrail trackers.
StatsdStats::getInstance().setUidMapChanges(0);
- StatsdStats::getInstance().setUidMapSnapshots(1);
mBytesUsed = 0;
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
}
int64_t UidMap::getMinimumTimestampNs() {
int64_t m = 0;
- for (auto it : mLastUpdatePerConfigKey) {
+ for (const auto& kv : mLastUpdatePerConfigKey) {
if (m == 0) {
- m = it.second;
- } else if (it.second < m) {
- m = it.second;
+ m = kv.second;
+ } else if (kv.second < m) {
+ m = kv.second;
}
}
return m;
@@ -315,10 +309,6 @@
return mBytesUsed;
}
-void UidMap::appendUidMap(const ConfigKey& key, ProtoOutputStream* proto) {
- appendUidMap(getElapsedRealtimeNs(), key, proto);
-}
-
void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
ProtoOutputStream* proto) {
lock_guard<mutex> lock(mMutex); // Lock for updates
@@ -332,34 +322,27 @@
(long long)record.timestampNs);
proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_NEW_VERSION, (int)record.version);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_PREV_VERSION, (int)record.prevVersion);
proto->end(changesToken);
}
}
- bool atLeastOneSnapshot = false;
- unsigned int count = 0;
- for (const SnapshotRecord& record : mSnapshots) {
- // Ensure that we include at least the latest snapshot.
- if ((count == mSnapshots.size() - 1 && !atLeastOneSnapshot) ||
- record.timestampNs > mLastUpdatePerConfigKey[key]) {
- uint64_t snapshotsToken =
- proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
- atLeastOneSnapshot = true;
- count++;
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
- (long long)record.timestampNs);
- for (const SnapshotPackageInfo& info : record.infos) {
- uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
- FIELD_ID_SNAPSHOT_PACKAGE_INFO);
- proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, info.package);
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, info.version);
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, info.uid);
- proto->end(token);
- }
- proto->end(snapshotsToken);
- }
+ // Write snapshot from current uid map state.
+ uint64_t snapshotsToken =
+ proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
+ for (const auto& kv : mMap) {
+ uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+ proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
+ (int)kv.second.versionCode);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
+ proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
+ proto->end(token);
}
+ proto->end(snapshotsToken);
int64_t prevMin = getMinimumTimestampNs();
mLastUpdatePerConfigKey[key] = timestamp;
@@ -368,14 +351,6 @@
if (newMin > prevMin) { // Delete anything possible now that the minimum has
// moved forward.
int64_t cutoff_nanos = newMin;
- for (auto it_snapshots = mSnapshots.begin(); it_snapshots != mSnapshots.end();) {
- if (it_snapshots->timestampNs < cutoff_nanos) {
- mBytesUsed -= it_snapshots->bytes;
- it_snapshots = mSnapshots.erase(it_snapshots);
- } else {
- ++it_snapshots;
- }
- }
for (auto it_changes = mChanges.begin(); it_changes != mChanges.end();) {
if (it_changes->timestampNs < cutoff_nanos) {
mBytesUsed -= kBytesChangeRecord;
@@ -384,53 +359,24 @@
++it_changes;
}
}
-
- if (mSnapshots.size() == 0) {
- // Produce another snapshot. This results in extra data being uploaded but
- // helps ensure we can re-construct the UID->app name, versionCode mapping
- // in server.
- vector<const SnapshotPackageInfo> infos;
- for (const auto& it : mMap) {
- infos.emplace_back(it.second.packageName, it.second.versionCode, it.first);
- }
-
- mSnapshots.emplace_back(timestamp, infos);
- mBytesUsed += mSnapshots.back().bytes;
- }
}
StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
StatsdStats::getInstance().setUidMapChanges(mChanges.size());
- StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
}
void UidMap::printUidMap(FILE* out) const {
lock_guard<mutex> lock(mMutex);
- for (auto it : mMap) {
- fprintf(out, "%s, v%" PRId64 " (%i)\n", it.second.packageName.c_str(),
- it.second.versionCode, it.first);
+ for (const auto& kv : mMap) {
+ if (!kv.second.deleted) {
+ fprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
+ kv.first.first);
+ }
}
}
void UidMap::OnConfigUpdated(const ConfigKey& key) {
mLastUpdatePerConfigKey[key] = -1;
-
- // Ensure there is at least one snapshot available since this configuration also needs to know
- // what all the uid's represent.
- if (mSnapshots.size() == 0) {
- sp<IStatsCompanionService> statsCompanion = nullptr;
- // Get statscompanion service from service manager
- const sp<IServiceManager> sm(defaultServiceManager());
- if (sm != nullptr) {
- const String16 name("statscompanion");
- statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
- if (statsCompanion == nullptr) {
- ALOGW("statscompanion service unavailable!");
- return;
- }
- statsCompanion->triggerUidSnapshot();
- }
- }
}
void UidMap::OnConfigRemoved(const ConfigKey& key) {
@@ -441,9 +387,9 @@
lock_guard<mutex> lock(mMutex);
set<int32_t> results;
- for (const auto& pair : mMap) {
- if (pair.second.packageName == package) {
- results.insert(pair.first);
+ for (const auto& kv : mMap) {
+ if (kv.first.second == package && !kv.second.deleted) {
+ results.insert(kv.first.first);
}
}
return results;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index a3632d2..7222e85 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -43,10 +43,13 @@
namespace statsd {
struct AppData {
- const string packageName;
int64_t versionCode;
+ bool deleted;
- AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
+ // Empty constructor needed for unordered map.
+ AppData() {
+ }
+ AppData(const int64_t v) : versionCode(v), deleted(false){};
};
// When calling appendUidMap, we retrieve all the ChangeRecords since the last
@@ -57,55 +60,21 @@
const string package;
const int32_t uid;
const int32_t version;
+ const int32_t prevVersion;
ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package,
- const int32_t uid, const int32_t version)
+ const int32_t uid, const int32_t version, const int32_t prevVersion)
: deletion(isDeletion),
timestampNs(timestampNs),
package(package),
uid(uid),
- version(version) {
+ version(version),
+ prevVersion(prevVersion) {
}
};
const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord);
-// Storing the int64 for a timestamp is expected to take 10 bytes (could take
-// less because of varint encoding).
-const unsigned int kBytesTimestampField = 10;
-
-struct SnapshotPackageInfo {
- const string package;
- const int32_t version;
- const int32_t uid;
- SnapshotPackageInfo(const string& package, const int32_t version, const int32_t uid)
- : package(package), version(version), uid(uid) {
- }
-};
-
-const unsigned int kBytesSnapshotInfo = sizeof(struct SnapshotPackageInfo);
-
-// When calling appendUidMap, we retrieve all the snapshots since the last
-// timestamp we called appendUidMap for this configuration key.
-struct SnapshotRecord {
- const int64_t timestampNs;
-
- // All the package info known.
- vector<const SnapshotPackageInfo> infos;
-
- // Tracks the number of bytes this snapshot consumes.
- uint32_t bytes;
-
- SnapshotRecord(const int64_t timestampNs, vector<const SnapshotPackageInfo>& infos)
- : timestampNs(timestampNs), infos(infos) {
- bytes = 0;
- for (auto info : infos) {
- bytes += info.package.size() + kBytesSnapshotInfo;
- }
- bytes += kBytesTimestampField;
- }
-};
-
// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
// at any given moment. This map must be updated by StatsCompanionService.
class UidMap : public virtual android::RefBase {
@@ -117,11 +86,12 @@
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
*/
- void updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
- const vector<String16>& packageName);
+ void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
+ const vector<int64_t>& versionCode, const vector<String16>& packageName);
- void updateApp(const String16& packageName, const int32_t& uid, const int64_t& versionCode);
- void removeApp(const String16& packageName, const int32_t& uid);
+ void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
+ const int64_t& versionCode);
+ void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
// Returns true if the given uid contains the specified app (eg. com.google.android.gms).
bool hasApp(int uid, const string& packageName) const;
@@ -157,7 +127,8 @@
// Gets all snapshots and changes that have occurred since the last output.
// If every config key has received a change or snapshot record, then this
// record is deleted.
- void appendUidMap(const ConfigKey& key, util::ProtoOutputStream* proto);
+ void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+ util::ProtoOutputStream* proto);
// Forces the output to be cleared. We still generate a snapshot based on the current state.
// This results in extra data uploaded but helps us reconstruct the uid mapping on the server
@@ -173,25 +144,20 @@
std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
string normalizeAppName(const string& appName) const;
- void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
- const vector<int64_t>& versionCode, const vector<String16>& packageName);
-
- void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
- const int64_t& versionCode);
- void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
-
- void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
- util::ProtoOutputStream* proto);
-
void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
// TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
mutable mutex mMutex;
mutable mutex mIsolatedMutex;
- // Maps uid to application data. This must be multimap since there is a feature in Android for
- // multiple apps to share the same uid.
- std::unordered_multimap<int, AppData> mMap;
+ struct PairHash {
+ size_t operator()(std::pair<int, string> p) const noexcept {
+ std::hash<std::string> hash_fn;
+ return hash_fn(std::to_string(p.first) + p.second);
+ }
+ };
+ // Maps uid and package name to application data.
+ std::unordered_map<std::pair<int, string>, AppData, PairHash> mMap;
// Maps isolated uid to the parent uid. Any metrics for an isolated uid will instead contribute
// to the parent uid.
@@ -200,8 +166,8 @@
// Record the changes that can be provided with the uploads.
std::list<ChangeRecord> mChanges;
- // Record the snapshots that can be provided with the uploads.
- std::list<SnapshotRecord> mSnapshots;
+ // Store which uid and apps represent deleted ones.
+ std::list<std::pair<int, string>> mDeletedApps;
// Metric producers that should be notified if there's an upgrade in any app.
set<wp<PackageInfoListener>> mSubscribers;
@@ -228,6 +194,8 @@
// Allows unit-test to access private methods.
FRIEND_TEST(UidMapTest, TestClearingOutput);
+ FRIEND_TEST(UidMapTest, TestRemovedAppRetained);
+ FRIEND_TEST(UidMapTest, TestRemovedAppOverGuardrail);
FRIEND_TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot);
FRIEND_TEST(UidMapTest, TestMemoryComputed);
FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 8213252..36b24c8 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -155,6 +155,8 @@
optional int64 version = 2;
optional int32 uid = 3;
+
+ optional bool deleted = 4;
}
optional int64 elapsed_timestamp_nanos = 1;
@@ -169,7 +171,8 @@
optional string app = 3;
optional int32 uid = 4;
- optional int64 version = 5;
+ optional int64 new_version = 5;
+ optional int64 prev_version = 6;
}
repeated Change changes = 2;
}
@@ -240,10 +243,10 @@
optional int32 matcher_count = 7;
optional int32 alert_count = 8;
optional bool is_valid = 9;
-
repeated int32 broadcast_sent_time_sec = 10;
repeated int32 data_drop_time_sec = 11;
repeated int32 dump_report_time_sec = 12;
+ repeated int32 dump_report_data_size = 20;
repeated MatcherStats matcher_stats = 13;
repeated ConditionStats condition_stats = 14;
repeated MetricStats metric_stats = 15;
@@ -266,11 +269,10 @@
repeated AtomStats atom_stats = 7;
message UidMapStats {
- optional int32 snapshots = 1;
- optional int32 changes = 2;
- optional int32 bytes_used = 3;
- optional int32 dropped_snapshots = 4;
- optional int32 dropped_changes = 5;
+ optional int32 changes = 1;
+ optional int32 bytes_used = 2;
+ optional int32 dropped_changes = 3;
+ optional int32 deleted_apps = 4;
}
optional UidMapStats uidmap_stats = 8;
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index b0da07b..4c6671d 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -146,11 +146,10 @@
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("pkg0");
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
- uidMap.updateMap({1111, 1111, 2222, 3333, 3333} /* uid list */,
- {1, 1, 2, 1, 2} /* version list */,
- {android::String16("pkg0"), android::String16("pkg1"),
- android::String16("pkg1"), android::String16("Pkg2"),
- android::String16("PkG3")} /* package name list */);
+ uidMap.updateMap(
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+ android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
@@ -297,7 +296,7 @@
TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
UidMap uidMap;
uidMap.updateMap(
- {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
@@ -372,7 +371,7 @@
TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
UidMap uidMap;
uidMap.updateMap(
- {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+ 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index e6fe3d8..fb8877a 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -126,7 +126,7 @@
TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
// Setup simple config key corresponding to empty config.
sp<UidMap> m = new UidMap();
- m->updateMap({1, 2}, {1, 2}, {String16("p1"), String16("p2")});
+ m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")});
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> subscriberAlarmMonitor;
int broadcastCount = 0;
@@ -139,7 +139,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, &bytes);
+ p.onDumpReport(key, 1, false, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -167,7 +167,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, &bytes);
+ p.onDumpReport(key, 1, false, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index a9b67e0..2fab975 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -76,7 +76,7 @@
apps.push_back(String16(kApp2.c_str()));
versions.push_back(4);
versions.push_back(5);
- m.updateMap(uids, versions, apps);
+ m.updateMap(1, uids, versions, apps);
EXPECT_TRUE(m.hasApp(1000, kApp1));
EXPECT_TRUE(m.hasApp(1000, kApp2));
EXPECT_FALSE(m.hasApp(1000, "not.app"));
@@ -102,7 +102,7 @@
apps.push_back(String16(kApp2.c_str()));
versions.push_back(4);
versions.push_back(5);
- m.updateMap(uids, versions, apps);
+ m.updateMap(1, uids, versions, apps);
std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
EXPECT_EQ(name_set.size(), 2u);
@@ -110,7 +110,7 @@
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
// Update the app1 version.
- m.updateApp(String16(kApp1.c_str()), 1000, 40);
+ m.updateApp(2, String16(kApp1.c_str()), 1000, 40);
EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -118,7 +118,7 @@
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
- m.removeApp(String16(kApp1.c_str()), 1000);
+ m.removeApp(3, String16(kApp1.c_str()), 1000);
EXPECT_FALSE(m.hasApp(1000, kApp1));
EXPECT_TRUE(m.hasApp(1000, kApp2));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -127,7 +127,7 @@
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
// Remove app2.
- m.removeApp(String16(kApp2.c_str()), 1000);
+ m.removeApp(4, String16(kApp2.c_str()), 1000);
EXPECT_FALSE(m.hasApp(1000, kApp1));
EXPECT_FALSE(m.hasApp(1000, kApp2));
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -136,14 +136,14 @@
TEST(UidMapTest, TestUpdateApp) {
UidMap m;
- m.updateMap({1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())});
+ m.updateMap(1, {1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())});
std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
EXPECT_EQ(name_set.size(), 2u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
// Adds a new name for uid 1000.
- m.updateApp(String16("NeW_aPP1_NAmE"), 1000, 40);
+ m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40);
name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
EXPECT_EQ(name_set.size(), 3u);
EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
@@ -152,7 +152,7 @@
EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
// This name is also reused by another uid 2000.
- m.updateApp(String16("NeW_aPP1_NAmE"), 2000, 1);
+ m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1);
name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */);
EXPECT_EQ(name_set.size(), 1u);
EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
@@ -200,6 +200,66 @@
EXPECT_EQ(1, results.snapshots_size());
}
+TEST(UidMapTest, TestRemovedAppRetained) {
+ UidMap m;
+ // Initialize single config key.
+ ConfigKey config1(1, StringToId("config1"));
+ m.OnConfigUpdated(config1);
+ vector<int32_t> uids;
+ vector<int64_t> versions;
+ vector<String16> apps;
+ uids.push_back(1000);
+ apps.push_back(String16(kApp2.c_str()));
+ versions.push_back(5);
+ m.updateMap(1, uids, versions, apps);
+ m.removeApp(2, String16(kApp2.c_str()), 1000);
+
+ ProtoOutputStream proto;
+ m.appendUidMap(3, config1, &proto);
+
+ // Snapshot should still contain this item as deleted.
+ UidMapping results;
+ protoOutputStreamToUidMapping(&proto, &results);
+ EXPECT_EQ(1, results.snapshots(0).package_info_size());
+ EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
+}
+
+TEST(UidMapTest, TestRemovedAppOverGuardrail) {
+ UidMap m;
+ // Initialize single config key.
+ ConfigKey config1(1, StringToId("config1"));
+ m.OnConfigUpdated(config1);
+ vector<int32_t> uids;
+ vector<int64_t> versions;
+ vector<String16> apps;
+ const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap;
+ for (int j = 0; j < maxDeletedApps + 10; j++) {
+ uids.push_back(j);
+ apps.push_back(String16(kApp1.c_str()));
+ versions.push_back(j);
+ }
+ m.updateMap(1, uids, versions, apps);
+
+ // First, verify that we have the expected number of items.
+ UidMapping results;
+ ProtoOutputStream proto;
+ m.appendUidMap(3, config1, &proto);
+ protoOutputStreamToUidMapping(&proto, &results);
+ EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
+
+ // Now remove all the apps.
+ m.updateMap(1, uids, versions, apps);
+ for (int j = 0; j < maxDeletedApps + 10; j++) {
+ m.removeApp(4, String16(kApp1.c_str()), j);
+ }
+
+ proto.clear();
+ m.appendUidMap(5, config1, &proto);
+ // Snapshot drops the first nine items.
+ protoOutputStreamToUidMapping(&proto, &results);
+ EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
+}
+
TEST(UidMapTest, TestClearingOutput) {
UidMap m;
@@ -218,7 +278,6 @@
versions.push_back(4);
versions.push_back(5);
m.updateMap(1, uids, versions, apps);
- EXPECT_EQ(1U, m.mSnapshots.size());
ProtoOutputStream proto;
m.appendUidMap(2, config1, &proto);
@@ -227,7 +286,6 @@
EXPECT_EQ(1, results.snapshots_size());
// We have to keep at least one snapshot in memory at all times.
- EXPECT_EQ(1U, m.mSnapshots.size());
proto.clear();
m.appendUidMap(2, config1, &proto);
protoOutputStreamToUidMapping(&proto, &results);
@@ -262,7 +320,6 @@
EXPECT_EQ(1, results.snapshots_size());
EXPECT_EQ(2, results.changes_size());
// At this point both should be cleared.
- EXPECT_EQ(1U, m.mSnapshots.size());
EXPECT_EQ(0U, m.mChanges.size());
}
@@ -280,11 +337,8 @@
apps.push_back(String16(kApp1.c_str()));
versions.push_back(1);
m.updateMap(1, uids, versions, apps);
- size_t snapshot_bytes = m.mBytesUsed;
- EXPECT_TRUE(snapshot_bytes > startBytes);
m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
- EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
ProtoOutputStream proto;
vector<uint8_t> bytes;
@@ -313,16 +367,13 @@
versions.push_back(1);
}
m.updateMap(1, uids, versions, apps);
- EXPECT_EQ(1U, m.mSnapshots.size());
m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2);
- EXPECT_EQ(1U, m.mSnapshots.size());
EXPECT_EQ(1U, m.mChanges.size());
// Now force deletion by limiting the memory to hold one delta change.
m.maxBytesOverride = 80; // Since the app string alone requires >45 characters.
m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
- EXPECT_EQ(0U, m.mSnapshots.size());
EXPECT_EQ(1U, m.mChanges.size());
}
#else
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a04a6f9..4dd0da8 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -18,6 +18,7 @@
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
+#include <iostream>
#include <vector>
namespace android {
@@ -66,14 +67,10 @@
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
// Here it assumes that GMS core has two uids.
- processor->getUidMap()->updateApp(
- android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("app1"), 111 /* uid */, 2 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")});
// GMS core node is in the middle.
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
@@ -147,7 +144,7 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
@@ -212,14 +209,10 @@
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
// Here it assumes that GMS core has two uids.
- processor->getUidMap()->updateApp(
- android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("app1"), 111 /* uid */, 2 /* version code*/);
- processor->getUidMap()->updateApp(
- android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")});
// GMS core node is in the middle.
std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
@@ -293,7 +286,7 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
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 63e23ce..eb57d470 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
@@ -172,7 +172,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -488,7 +489,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -731,7 +733,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
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 c2334d8..9729a2e 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
@@ -130,7 +130,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -342,7 +342,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -521,7 +521,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -718,7 +718,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
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 ab37140..4e2c36e 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -142,7 +142,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -433,7 +434,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
+ &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -650,7 +652,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 2b91324..18a0485 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -148,7 +148,7 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 1440f29..1952a6f 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, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
@@ -314,7 +314,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
new file mode 100644
index 0000000..d4892ed
--- /dev/null
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2017 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.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/StatsService.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+const string kApp1 = "app1.sharing.1";
+const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
+
+void SendConfig(StatsService& service, const StatsdConfig& config) {
+ string str;
+ config.SerializeToString(&str);
+ std::vector<uint8_t> configAsVec(str.begin(), str.end());
+ bool success;
+ service.addConfiguration(kConfigKey, configAsVec, &success);
+}
+
+ConfigMetricsReport GetReports(StatsService& service) {
+ vector<uint8_t> output;
+ service.getData(kConfigKey, &output);
+ ConfigMetricsReportList reports;
+ reports.ParseFromArray(output.data(), output.size());
+ EXPECT_EQ(1, reports.reports_size());
+ return reports.reports(0);
+}
+
+StatsdConfig MakeConfig() {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher = CreateProcessCrashAtomMatcher();
+ *config.add_atom_matcher() = appCrashMatcher;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(StringToId("AppCrashes"));
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(FIVE_MINUTES);
+ return config;
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
+ StatsService service(nullptr);
+ SendConfig(service, MakeConfig());
+ const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
+
+ ConfigMetricsReport report = GetReports(service);
+ // Expect no metrics since the bucket has not finished yet.
+ EXPECT_EQ(0, report.metrics_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
+ StatsService service(nullptr);
+ SendConfig(service, MakeConfig());
+ const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ // Force the uidmap to update at timestamp 2.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+ // This is a new installation, so there shouldn't be a split (should be same as the without
+ // split case).
+ service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
+ // Goes into the second bucket.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+ ConfigMetricsReport report = GetReports(service);
+ EXPECT_EQ(0, report.metrics_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
+ StatsService service(nullptr);
+ SendConfig(service, MakeConfig());
+ const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
+
+ // Force the uidmap to update at timestamp 2.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+ service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
+ // Goes into the second bucket.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+ ConfigMetricsReport report = GetReports(service);
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
+ StatsService service(nullptr);
+ SendConfig(service, MakeConfig());
+ const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
+
+ // Force the uidmap to update at timestamp 2.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+ service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
+ // Goes into the second bucket.
+ service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+ ConfigMetricsReport report = GetReports(service);
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index bfae8bc..f2d47c7 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -127,7 +127,7 @@
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -161,7 +161,7 @@
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
@@ -208,7 +208,7 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
@@ -237,7 +237,7 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -262,7 +262,7 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
@@ -304,7 +304,7 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
EXPECT_EQ(reports.reports_size(), 1);
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 5c35d96..e99e402 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -129,9 +129,9 @@
stats.noteDataDropped(key);
// dump report -> 3
- stats.noteMetricsReportSent(key);
- stats.noteMetricsReportSent(key);
- stats.noteMetricsReportSent(key);
+ stats.noteMetricsReportSent(key, 0);
+ stats.noteMetricsReportSent(key, 0);
+ stats.noteMetricsReportSent(key, 0);
vector<uint8_t> output;
stats.dumpStats(&output, true); // Dump and reset stats
@@ -143,6 +143,7 @@
EXPECT_EQ(2, configReport.broadcast_sent_time_sec_size());
EXPECT_EQ(1, configReport.data_drop_time_sec_size());
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
+ EXPECT_EQ(3, configReport.dump_report_data_size_size());
EXPECT_EQ(1, configReport.annotation_size());
EXPECT_EQ(123, configReport.annotation(0).field_int64());
EXPECT_EQ(456, configReport.annotation(0).field_int32());
@@ -268,7 +269,7 @@
for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
stats.noteDataDropped(key, timestamps[i]);
stats.noteBroadcastSent(key, timestamps[i]);
- stats.noteMetricsReportSent(key, timestamps[i]);
+ stats.noteMetricsReportSent(key, 0, timestamps[i]);
}
int32_t newTimestamp = 10000;
@@ -276,7 +277,7 @@
// now it should trigger removing oldest timestamp
stats.noteDataDropped(key, 10000);
stats.noteBroadcastSent(key, 10000);
- stats.noteMetricsReportSent(key, 10000);
+ stats.noteMetricsReportSent(key, 0, 10000);
EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
const auto& configStats = stats.mConfigStats[key];
@@ -284,7 +285,7 @@
size_t maxCount = StatsdStats::kMaxTimestampCount;
EXPECT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
EXPECT_EQ(maxCount, configStats->data_drop_time_sec.size());
- EXPECT_EQ(maxCount, configStats->dump_report_time_sec.size());
+ EXPECT_EQ(maxCount, configStats->dump_report_stats.size());
// the oldest timestamp is the second timestamp in history
EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
@@ -294,7 +295,7 @@
// the last timestamp is the newest timestamp.
EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
- EXPECT_EQ(newTimestamp, configStats->dump_report_time_sec.back());
+ EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
}
} // namespace statsd
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9017736..479fe27 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -763,7 +763,6 @@
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
Landroid/graphics/GraphicBuffer;->mNativeObject:J
-Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
Landroid/graphics/LinearGradient;->mColors:[I
Landroid/graphics/Matrix;->native_instance:J
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4326ee3..86fedb1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6678,7 +6678,8 @@
public RemoteViews makeContentView(boolean increasedHeight) {
mBuilder.mOriginalActions = mBuilder.mActions;
mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
+ RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+ true /* showReplyIcon */);
mBuilder.mActions = mBuilder.mOriginalActions;
mBuilder.mOriginalActions = null;
return remoteViews;
@@ -6765,11 +6766,19 @@
*/
@Override
public RemoteViews makeBigContentView() {
- return makeMessagingView(false /* isCollapsed */);
+ return makeMessagingView(false /* displayImagesAtEnd */, false /* showReplyIcon */);
}
+ /**
+ * Create a messaging layout.
+ *
+ * @param displayImagesAtEnd should images be displayed at the end of the content instead
+ * of inline.
+ * @param showReplyIcon Should the reply affordance be shown at the end of the notification
+ * @return the created remoteView.
+ */
@NonNull
- private RemoteViews makeMessagingView(boolean isCollapsed) {
+ private RemoteViews makeMessagingView(boolean displayImagesAtEnd, boolean showReplyIcon) {
CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
@@ -6780,24 +6789,24 @@
nameReplacement = conversationTitle;
conversationTitle = null;
}
- boolean hideLargeIcon = !isCollapsed || isOneToOne;
+ boolean hideLargeIcon = !showReplyIcon || isOneToOne;
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
mBuilder.getMessagingLayoutResource(),
mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
.hideLargeIcon(hideLargeIcon)
.headerTextSecondary(conversationTitle)
- .alwaysShowReply(isCollapsed));
+ .alwaysShowReply(showReplyIcon));
addExtras(mBuilder.mN.extras);
// also update the end margin if there is an image
int endMargin = R.dimen.notification_content_margin_end;
- if (isCollapsed) {
+ if (showReplyIcon) {
endMargin = R.dimen.notification_content_plus_picture_margin_end;
}
contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.resolveContrastColor());
- contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
- isCollapsed);
+ contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
+ displayImagesAtEnd);
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
mBuilder.mN.mLargeIcon);
contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
@@ -6864,7 +6873,8 @@
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
+ RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+ false /* showReplyIcon */);
remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
return remoteViews;
}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index e0654fd..ade6374 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -684,14 +684,15 @@
* tunneled traffic.
*
* @param address the local address for traffic inside the tunnel
+ * @param prefixLen length of the InetAddress prefix
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
- public void addAddress(@NonNull LinkAddress address) throws IOException {
+ public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
try {
mService.addAddressToTunnelInterface(
- mResourceId, address, mOpPackageName);
+ mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -703,14 +704,15 @@
* <p>Remove an address which was previously added to the IpSecTunnelInterface
*
* @param address to be removed
+ * @param prefixLen length of the InetAddress prefix
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
- public void removeAddress(@NonNull LinkAddress address) throws IOException {
+ public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
try {
mService.removeAddressFromTunnelInterface(
- mResourceId, address, mOpPackageName);
+ mResourceId, new LinkAddress(address, prefixLen), mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a99ae2e..b2a2c60 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12541,6 +12541,19 @@
*/
public static final String SWAP_ENABLED = "swap_enabled";
+ /**
+ * Blacklist of GNSS satellites.
+ *
+ * This is a list of integers separated by commas to represent pairs of (constellation,
+ * svid). Thus, the number of integers should be even.
+ *
+ * E.g.: "3,0,5,24" denotes (constellation=3, svid=0) and (constellation=5, svid=24) are
+ * blacklisted. Note that svid=0 denotes all svids in the
+ * constellation are blacklisted.
+ *
+ * @hide
+ */
+ public static final String GNSS_SATELLITE_BLACKLIST = "gnss_satellite_blacklist";
}
/**
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 239beaa..f73b607 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -64,7 +64,7 @@
private boolean mIsHidingAnimated;
private boolean mNeedsGeneratedAvatar;
private Notification.Person mSender;
- private boolean mAvatarsAtEnd;
+ private boolean mImagesAtEnd;
private ViewGroup mImageContainer;
private MessagingImageMessage mIsolatedMessage;
private boolean mTransformingImages;
@@ -342,7 +342,7 @@
mAddedMessages.add(message);
}
boolean isImage = message instanceof MessagingImageMessage;
- if (mAvatarsAtEnd && isImage) {
+ if (mImagesAtEnd && isImage) {
isolatedMessage = (MessagingImageMessage) message;
} else {
if (removeFromParentIfDifferent(message, mMessageContainer)) {
@@ -474,9 +474,9 @@
mTransformingImages = transformingImages;
}
- public void setDisplayAvatarsAtEnd(boolean atEnd) {
- if (mAvatarsAtEnd != atEnd) {
- mAvatarsAtEnd = atEnd;
+ public void setDisplayImagesAtEnd(boolean atEnd) {
+ if (mImagesAtEnd != atEnd) {
+ mImagesAtEnd = atEnd;
mImageContainer.setVisibility(atEnd ? View.VISIBLE : View.GONE);
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 5279636..292df60 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -81,7 +81,7 @@
private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
private Notification.Person mUser;
private CharSequence mNameReplacement;
- private boolean mIsCollapsed;
+ private boolean mDisplayImagesAtEnd;
public MessagingLayout(@NonNull Context context) {
super(context);
@@ -128,8 +128,8 @@
}
@RemotableViewMethod
- public void setIsCollapsed(boolean isCollapsed) {
- mIsCollapsed = isCollapsed;
+ public void setDisplayImagesAtEnd(boolean atEnd) {
+ mDisplayImagesAtEnd = atEnd;
}
@RemotableViewMethod
@@ -337,7 +337,7 @@
newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
mAddedGroups.add(newGroup);
}
- newGroup.setDisplayAvatarsAtEnd(mIsCollapsed);
+ newGroup.setDisplayImagesAtEnd(mDisplayImagesAtEnd);
newGroup.setLayoutColor(mLayoutColor);
Notification.Person sender = senders.get(groupIndex);
CharSequence nameOverride = null;
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 825b7a0..3ea6049 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -116,9 +116,10 @@
const auto& info = decoder->mCodec->getInfo();
const int width = info.width();
const int height = info.height();
+ const bool isNinePatch = decoder->mPeeker->mPatch != nullptr;
return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
reinterpret_cast<jlong>(decoder.release()), width, height,
- animated);
+ animated, isNinePatch);
}
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
@@ -332,13 +333,6 @@
}
}
- float scaleX = 1.0f;
- float scaleY = 1.0f;
- if (scale) {
- scaleX = (float) desiredWidth / decodeInfo.width();
- scaleY = (float) desiredHeight / decodeInfo.height();
- }
-
jbyteArray ninePatchChunk = nullptr;
jobject ninePatchInsets = nullptr;
@@ -346,9 +340,6 @@
if (!jpostProcess) {
// FIXME: Share more code with BitmapFactory.cpp.
if (decoder->mPeeker->mPatch != nullptr) {
- if (scale) {
- decoder->mPeeker->scale(scaleX, scaleY, desiredWidth, desiredHeight);
- }
size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
ninePatchChunk = env->NewByteArray(ninePatchArraySize);
if (ninePatchChunk == nullptr) {
@@ -408,7 +399,12 @@
SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
canvas.translate(translateX, translateY);
- canvas.scale(scaleX, scaleY);
+ if (scale) {
+ float scaleX = (float) desiredWidth / decodeInfo.width();
+ float scaleY = (float) desiredHeight / decodeInfo.height();
+ canvas.scale(scaleX, scaleY);
+ }
+
canvas.drawBitmap(bm, 0.0f, 0.0f, &paint);
bm.swap(scaledBm);
@@ -532,7 +528,7 @@
int register_android_graphics_ImageDecoder(JNIEnv* env) {
gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
- gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZ)V");
+ gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b5303c8..05686a0 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -451,6 +451,7 @@
// If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
// Secure#LOCATION_MODE_OFF} temporarily for all users.
optional SettingProto global_kill_switch = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto gnss_satellite_blacklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Location location = 69;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 002c9e2..b1936b9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -239,6 +239,7 @@
Settings.Global.GLOBAL_HTTP_PROXY_HOST,
Settings.Global.GLOBAL_HTTP_PROXY_PAC,
Settings.Global.GLOBAL_HTTP_PROXY_PORT,
+ Settings.Global.GNSS_SATELLITE_BLACKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index ecd443c..098f100 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -748,6 +748,7 @@
private final int mWidth;
private final int mHeight;
private final boolean mAnimated;
+ private final boolean mIsNinePatch;
private int mDesiredWidth;
private int mDesiredHeight;
@@ -778,13 +779,14 @@
*/
@SuppressWarnings("unused")
private ImageDecoder(long nativePtr, int width, int height,
- boolean animated) {
+ boolean animated, boolean isNinePatch) {
mNativePtr = nativePtr;
mWidth = width;
mHeight = height;
mDesiredWidth = width;
mDesiredHeight = height;
mAnimated = animated;
+ mIsNinePatch = isNinePatch;
mCloseGuard.open("close");
}
@@ -1665,7 +1667,7 @@
// this call potentially manipulates the decoder so it must be performed prior to
// decoding the bitmap and after decode set the density on the resulting bitmap
- final int srcDensity = computeDensity(src, decoder);
+ final int srcDensity = decoder.computeDensity(src);
if (decoder.mAnimated) {
// AnimatedImageDrawable calls postProcessAndRelease only if
// mPostProcessor exists.
@@ -1755,7 +1757,7 @@
// this call potentially manipulates the decoder so it must be performed prior to
// decoding the bitmap
- final int srcDensity = computeDensity(src, decoder);
+ final int srcDensity = decoder.computeDensity(src);
Bitmap bm = decoder.decodeBitmapInternal();
bm.setDensity(srcDensity);
@@ -1772,12 +1774,26 @@
}
// This method may modify the decoder so it must be called prior to performing the decode
- private static int computeDensity(@NonNull Source src, @NonNull ImageDecoder decoder) {
+ private int computeDensity(@NonNull Source src) {
// if the caller changed the size then we treat the density as unknown
- if (decoder.requestedResize()) {
+ if (this.requestedResize()) {
return Bitmap.DENSITY_NONE;
}
+ final int srcDensity = src.getDensity();
+ if (srcDensity == Bitmap.DENSITY_NONE) {
+ return srcDensity;
+ }
+
+ // Scaling up nine-patch divs is imprecise and is better handled
+ // at draw time. An app won't be relying on the internal Bitmap's
+ // size, so it is safe to let NinePatchDrawable handle scaling.
+ // mPostProcessor disables nine-patching, so behave normally if
+ // it is present.
+ if (mIsNinePatch && mPostProcessor == null) {
+ return srcDensity;
+ }
+
// Special stuff for compatibility mode: if the target density is not
// the same as the display density, but the resource -is- the same as
// the display density, then don't scale it down to the target density.
@@ -1786,23 +1802,25 @@
// to the compatibility density only to have them scaled back up when
// drawn to the screen.
Resources res = src.getResources();
- final int srcDensity = src.getDensity();
if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
return srcDensity;
}
+ final int dstDensity = src.computeDstDensity();
+ if (srcDensity == dstDensity) {
+ return srcDensity;
+ }
+
// For P and above, only resize if it would be a downscale. Scale up prior
// to P in case the app relies on the Bitmap's size without considering density.
- final int dstDensity = src.computeDstDensity();
- if (srcDensity == Bitmap.DENSITY_NONE || srcDensity == dstDensity
- || (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P)) {
+ if (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P) {
return srcDensity;
}
float scale = (float) dstDensity / srcDensity;
- int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
- int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
- decoder.setTargetSize(scaledWidth, scaledHeight);
+ int scaledWidth = (int) (mWidth * scale + 0.5f);
+ int scaledHeight = (int) (mHeight * scale + 0.5f);
+ this.setTargetSize(scaledWidth, scaledHeight);
return dstDensity;
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index bc0e43b..7888436 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -66,7 +66,7 @@
/**
* This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
* <p>
- * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW and RAF.
+ * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF and HEIF.
* <p>
* Attribute mutation is supported for JPEG image files.
*/
@@ -2524,46 +2524,46 @@
private void getHeifAttributes(ByteOrderedDataInputStream in) throws IOException {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
- if (mSeekableFileDescriptor != null) {
- retriever.setDataSource(mSeekableFileDescriptor);
- } else {
- retriever.setDataSource(new MediaDataSource() {
- long mPosition;
+ retriever.setDataSource(new MediaDataSource() {
+ long mPosition;
- @Override
- public void close() throws IOException {}
+ @Override
+ public void close() throws IOException {}
- @Override
- public int readAt(long position, byte[] buffer, int offset, int size)
- throws IOException {
- if (size == 0) {
- return 0;
- }
- if (position < 0) {
- return -1;
- }
- if (mPosition != position) {
- in.seek(position);
- mPosition = position;
- }
-
- int bytesRead = in.read(buffer, offset, size);
- if (bytesRead < 0) {
- mPosition = -1; // need to seek on next read
- return -1;
- }
-
- mPosition += bytesRead;
- return bytesRead;
+ @Override
+ public int readAt(long position, byte[] buffer, int offset, int size)
+ throws IOException {
+ if (size == 0) {
+ return 0;
}
-
- @Override
- public long getSize() throws IOException {
+ if (position < 0) {
return -1;
}
- });
- }
+ if (mPosition != position) {
+ in.seek(position);
+ mPosition = position;
+ }
+ int bytesRead = in.read(buffer, offset, size);
+ if (bytesRead < 0) {
+ mPosition = -1; // need to seek on next read
+ return -1;
+ }
+
+ mPosition += bytesRead;
+ return bytesRead;
+ }
+
+ @Override
+ public long getSize() throws IOException {
+ return -1;
+ }
+ });
+
+ String exifOffsetStr = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET);
+ String exifLengthStr = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_EXIF_LENGTH);
String hasImage = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
String hasVideo = retriever.extractMetadata(
@@ -2622,6 +2622,30 @@
ExifAttribute.createUShort(orientation, mExifByteOrder));
}
+ if (exifOffsetStr != null && exifLengthStr != null) {
+ int offset = Integer.parseInt(exifOffsetStr);
+ int length = Integer.parseInt(exifLengthStr);
+ if (length <= 6) {
+ throw new IOException("Invalid exif length");
+ }
+ in.seek(offset);
+ byte[] identifier = new byte[6];
+ if (in.read(identifier) != 6) {
+ throw new IOException("Can't read identifier");
+ }
+ offset += 6;
+ length -= 6;
+ if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
+ throw new IOException("Invalid identifier");
+ }
+
+ byte[] bytes = new byte[length];
+ if (in.read(bytes) != length) {
+ throw new IOException("Can't read exif");
+ }
+ readExifSegment(bytes, IFD_TYPE_PRIMARY);
+ }
+
if (DEBUG) {
Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 0955dd6..8ab5ec4 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -890,5 +890,14 @@
*/
public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
+ /**
+ * @hide
+ */
+ public static final int METADATA_KEY_EXIF_OFFSET = 33;
+
+ /**
+ * @hide
+ */
+ public static final int METADATA_KEY_EXIF_LENGTH = 34;
// Add more here...
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 19ee151..67053d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -742,6 +742,9 @@
dumpSetting(s, p,
Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
GlobalSettingsProto.Location.GLOBAL_KILL_SWITCH);
+ dumpSetting(s, p,
+ Settings.Global.GNSS_SATELLITE_BLACKLIST,
+ GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
p.end(locationToken);
final long lpmToken = p.start(GlobalSettingsProto.LOW_POWER_MODE);
diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
index e765320..babaa9f 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
@@ -20,11 +20,11 @@
android:viewportWidth="53.0"
android:viewportHeight="48.0">
<path
- android:fillColor="?attr/singleToneColor"
+ android:fillColor="#FFF"
android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
<path
- android:fillColor="?attr/singleToneColor"
+ android:fillColor="#FFF"
android:pathData="M49.000000,40.000000l4.000000,0.000000l0.000000,4.000000l-4.000000,0.000000z"/>
<path
- android:fillColor="?attr/singleToneColor"
+ android:fillColor="#FFF"
android:pathData="M49.000000,20.000000l4.000000,0.000000l0.000000,16.100000l-4.000000,0.000000z"/></vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
index b7b154c..08a9993 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
@@ -19,6 +19,6 @@
android:viewportWidth="53.0"
android:viewportHeight="48.0">
<path
- android:fillColor="?attr/singleToneColor"
+ android:fillColor="#FFF"
android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
</vector>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 107249b..ca5b034 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -71,6 +71,9 @@
private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
+ // Should match the values in PhoneWindowManager
+ public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
+
private final PackageManager mPackageManager;
private final BackgroundExecutor mBackgroundExecutor;
private final TaskStackChangeListeners mTaskStackChangeListeners;
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 6921836..d1d6609 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
@@ -165,7 +166,7 @@
title.setSelected(true);
final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
- if (subtitleText == null) {
+ if (TextUtils.isEmpty(subtitleText)) {
subtitle.setVisibility(View.GONE);
} else {
subtitle.setVisibility(View.VISIBLE);
@@ -173,11 +174,11 @@
}
final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
- if (descriptionText == null) {
- subtitle.setVisibility(View.VISIBLE);
+ if (TextUtils.isEmpty(descriptionText)) {
description.setVisibility(View.GONE);
} else {
- description.setText(mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION));
+ description.setVisibility(View.VISIBLE);
+ description.setText(descriptionText);
}
negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0f85c5b..8bb3c02 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -22,6 +22,7 @@
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.ActivityManager;
+import android.app.trust.TrustManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -51,6 +52,7 @@
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
+import com.android.systemui.SystemUIApplication;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
@@ -70,6 +72,7 @@
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -107,6 +110,7 @@
private Handler mHandler;
private RecentsImpl mImpl;
+ private TrustManager mTrustManager;
private int mDraggingInRecentsCurrentUser;
// Only For system user, this is the callbacks instance we return to each secondary user
@@ -235,6 +239,8 @@
registerWithSystemUser();
}
putComponent(Recents.class, this);
+
+ mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
}
@Override
@@ -342,12 +348,28 @@
// If connected to launcher service, let it handle the toggle logic
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null) {
- try {
- overviewProxy.onOverviewToggle();
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+ final Runnable toggleRecents = () -> {
+ try {
+ if (mOverviewProxyService.getProxy() != null) {
+ mOverviewProxyService.getProxy().onOverviewToggle();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+ }
+ };
+ // Preload only if device for current user is unlocked
+ final StatusBar statusBar = getComponent(StatusBar.class);
+ if (statusBar != null && statusBar.isKeyguardShowing()) {
+ statusBar.executeRunnableDismissingKeyguard(() -> {
+ // Flush trustmanager before checking device locked per user
+ mTrustManager.reportKeyguardShowingChanged();
+ mHandler.post(toggleRecents);
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */,
+ true /* deferred */);
+ } else {
+ toggleRecents.run();
}
+ return;
}
int growTarget = getComponent(Divider.class).getView().growsRecents();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 3dd6e35..bfbba7c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -107,7 +107,7 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index f81671b..51b4239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -142,12 +142,14 @@
if (mState.strengthId != state.strengthId) {
mMobileDrawable.setLevel(state.strengthId);
}
- if (mState.typeId != state.typeId && state.typeId != 0) {
- mMobileType.setContentDescription(state.typeContentDescription);
- mMobileType.setImageResource(state.typeId);
- mMobileType.setVisibility(View.VISIBLE);
- } else {
- mMobileType.setVisibility(View.GONE);
+ if (mState.typeId != state.typeId) {
+ if (state.typeId != 0) {
+ mMobileType.setContentDescription(state.typeContentDescription);
+ mMobileType.setImageResource(state.typeId);
+ mMobileType.setVisibility(View.VISIBLE);
+ } else {
+ mMobileType.setVisibility(View.GONE);
+ }
}
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 9adf923..8c257fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -370,11 +370,15 @@
float layoutEnd = getLayoutEnd();
float overflowStart = getMaxOverflowStart();
mVisualOverflowStart = 0;
+ mFirstVisibleIconState = null;
boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
iconState.xTranslation = translationX;
+ if (mFirstVisibleIconState == null) {
+ mFirstVisibleIconState = iconState;
+ }
boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
&& iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
boolean noOverflowAfter = i == childCount - 1;
@@ -401,7 +405,6 @@
mNumDots = 0;
if (firstOverflowIndex != -1) {
translationX = mVisualOverflowStart;
- mFirstVisibleIconState = null;
for (int i = firstOverflowIndex; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
@@ -416,9 +419,6 @@
}
translationX += (mNumDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth)
* iconState.iconAppearAmount;
- if (mFirstVisibleIconState == null) {
- mFirstVisibleIconState = iconState;
- }
mLastVisibleIconState = iconState;
} else {
iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 510af03..b4e7575 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -306,17 +306,6 @@
mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
}
- /**
- * For mobile essentially (an array of holders in one slot)
- */
- private void handleSet(int slotIndex, List<StatusBarIconHolder> holders) {
- for (StatusBarIconHolder holder : holders) {
- int viewIndex = getViewIndex(slotIndex, holder.getTag());
- mIconLogger.onIconVisibility(getSlotName(slotIndex), holder.isVisible());
- mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
- }
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG + " state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index c5a3a0d..94ac4f62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -414,7 +414,7 @@
@Override public String toString() {
return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
- + roaming + ", visible=" + visible + ")";
+ + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index da7dc07..d282f25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3023,6 +3023,11 @@
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
updateNotificationAnimationStates();
+ if (!animationsEnabled) {
+ mSwipedOutViews.clear();
+ mChildrenToRemoveAnimated.clear();
+ clearTemporaryViewsInGroup(this);
+ }
}
private void updateNotificationAnimationStates() {
@@ -3090,6 +3095,21 @@
@Override
public void changeViewPosition(View child, int newIndex) {
int currentIndex = indexOfChild(child);
+
+ if (currentIndex == -1) {
+ boolean isTransient = false;
+ if (child instanceof ExpandableNotificationRow
+ && ((ExpandableNotificationRow)child).getTransientContainer() != null) {
+ isTransient = true;
+ }
+ Log.e(TAG, "Attempting to re-position "
+ + (isTransient ? "transient" : "")
+ + " view {"
+ + child
+ + "}");
+ return;
+ }
+
if (child != null && child.getParent() == this && currentIndex != newIndex) {
mChangePositionInProgress = true;
((ExpandableView)child).setChangingPosition(true);
@@ -3569,17 +3589,17 @@
private void clearTemporaryViews() {
// lets make sure nothing is in the overlay / transient anymore
- clearTemporaryViews(this);
+ clearTemporaryViewsInGroup(this);
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- clearTemporaryViews(row.getChildrenContainer());
+ clearTemporaryViewsInGroup(row.getChildrenContainer());
}
}
}
- private void clearTemporaryViews(ViewGroup viewGroup) {
+ private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
viewGroup.removeTransientView(viewGroup.getTransientView(0));
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c66c7b0..a3dcd45 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5572,6 +5572,12 @@
// OS: P
ACTION_SETTINGS_SLICE_CHANGED = 1372;
+ // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically
+ // note: Wifi Scanning must be off for this dialog to show
+ // CATEGORY: SETTINGS
+ // OS: P
+ WIFI_SCANNING_NEEDED_DIALOG = 1373;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 75b651d..067566d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2645,6 +2645,8 @@
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
+ msg.getData().putCharSequence(
+ ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
mAm.mHandler.sendMessage(msg);
}
}
@@ -3563,13 +3565,15 @@
if (app != null) {
mAm.mAppErrors.appNotResponding(app, null, null, false,
- "Context.startForegroundService() did not then call Service.startForeground()");
+ "Context.startForegroundService() did not then call Service.startForeground(): "
+ + r);
}
}
- void serviceForegroundCrash(ProcessRecord app) {
+ void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
- "Context.startForegroundService() did not then call Service.startForeground()");
+ "Context.startForegroundService() did not then call Service.startForeground(): "
+ + serviceRecord);
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2e87a44..adf3480 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1920,6 +1920,8 @@
static final int FIRST_COMPAT_MODE_MSG = 300;
static final int FIRST_SUPERVISOR_STACK_MSG = 100;
+ static final String SERVICE_RECORD_KEY = "servicerecord";
+
static ServiceThread sKillThread = null;
static KillHandler sKillHandler = null;
@@ -2168,7 +2170,8 @@
mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
} break;
case SERVICE_FOREGROUND_CRASH_MSG: {
- mServices.serviceForegroundCrash((ProcessRecord)msg.obj);
+ mServices.serviceForegroundCrash(
+ (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
} break;
case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
RemoteCallbackList<IResultReceiver> callbacks
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index d1808d8..6ca8a92 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -36,7 +36,6 @@
import android.Manifest;
import android.app.ActivityOptions;
-import android.app.AppGlobals;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
@@ -342,9 +341,9 @@
private boolean interceptHarmfulAppIfNeeded() {
CharSequence harmfulAppWarning;
try {
- harmfulAppWarning = AppGlobals.getPackageManager().getHarmfulAppWarning(
- mAInfo.packageName, mUserId);
- } catch (RemoteException e) {
+ harmfulAppWarning = mService.getPackageManager()
+ .getHarmfulAppWarning(mAInfo.packageName, mUserId);
+ } catch (RemoteException ex) {
return false;
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5ba7380..58bca19 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -83,7 +83,11 @@
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.location.gnssmetrics.GnssMetrics;
+import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
+
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -99,14 +103,13 @@
import java.util.Map.Entry;
import java.util.Properties;
-import libcore.io.IoUtils;
-
/**
* A GNSS implementation of LocationProvider used by LocationManager.
*
* {@hide}
*/
-public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback {
+public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback,
+ GnssSatelliteBlacklistCallback {
private static final String TAG = "GnssLocationProvider";
@@ -308,7 +311,7 @@
}
}
- private Object mLock = new Object();
+ private final Object mLock = new Object();
// current status
private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
@@ -411,6 +414,7 @@
private final ILocationManager mILocationManager;
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusListenerHelper mListenerHelper;
+ private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
@@ -577,6 +581,16 @@
}
};
+ /**
+ * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
+ */
+ @Override
+ public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
+ mHandler.post(()->{
+ native_set_satellite_blacklist(constellations, svids);
+ });
+ }
+
private void subscriptionOrSimChanged(Context context) {
if (DEBUG) Log.d(TAG, "received SIM related action: ");
TelephonyManager phone = (TelephonyManager)
@@ -869,7 +883,10 @@
};
mGnssMetrics = new GnssMetrics(mBatteryStats);
- mNtpTimeHelper = new NtpTimeHelper(mContext, Looper.myLooper(), this);
+ mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
+ mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext,
+ looper, this);
+ mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
}
/**
@@ -2900,6 +2917,8 @@
private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
+ private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+
// GNSS Batching
private static native int native_get_batch_size();
diff --git a/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java b/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java
new file mode 100644
index 0000000..77951aa
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java
@@ -0,0 +1,102 @@
+package com.android.server.location;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Detects blacklist change and updates the blacklist.
+ */
+class GnssSatelliteBlacklistHelper {
+
+ private static final String TAG = "GnssBlacklistHelper";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String BLACKLIST_DELIMITER = ",";
+
+ private final Context mContext;
+ private final GnssSatelliteBlacklistCallback mCallback;
+
+ interface GnssSatelliteBlacklistCallback {
+ void onUpdateSatelliteBlacklist(int[] constellations, int[] svids);
+ }
+
+ GnssSatelliteBlacklistHelper(Context context, Looper looper,
+ GnssSatelliteBlacklistCallback callback) {
+ mContext = context;
+ mCallback = callback;
+ ContentObserver contentObserver = new ContentObserver(new Handler(looper)) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateSatelliteBlacklist();
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(
+ Settings.Global.GNSS_SATELLITE_BLACKLIST),
+ true,
+ contentObserver, UserHandle.USER_ALL);
+ }
+
+ void updateSatelliteBlacklist() {
+ ContentResolver resolver = mContext.getContentResolver();
+ String blacklist = Settings.Global.getString(
+ resolver,
+ Settings.Global.GNSS_SATELLITE_BLACKLIST);
+ if (blacklist == null) {
+ blacklist = "";
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("Update GNSS satellite blacklist: %s", blacklist));
+ }
+
+ List<Integer> blacklistValues;
+ try {
+ blacklistValues = parseSatelliteBlacklist(blacklist);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Exception thrown when parsing blacklist string.", e);
+ return;
+ }
+
+ if (blacklistValues.size() % 2 != 0) {
+ Log.e(TAG, "blacklist string has odd number of values."
+ + "Aborting updateSatelliteBlacklist");
+ return;
+ }
+
+ int length = blacklistValues.size() / 2;
+ int[] constellations = new int[length];
+ int[] svids = new int[length];
+ for (int i = 0; i < length; i++) {
+ constellations[i] = blacklistValues.get(i * 2);
+ svids[i] = blacklistValues.get(i * 2 + 1);
+ }
+ mCallback.onUpdateSatelliteBlacklist(constellations, svids);
+ }
+
+ @VisibleForTesting
+ static List<Integer> parseSatelliteBlacklist(String blacklist) throws NumberFormatException {
+ String[] strings = blacklist.split(BLACKLIST_DELIMITER);
+ List<Integer> parsed = new ArrayList<>(strings.length);
+ for (String string : strings) {
+ string = string.trim();
+ if (!"".equals(string)) {
+ int value = Integer.parseInt(string);
+ if (value < 0) {
+ throw new NumberFormatException("Negative value is invalid.");
+ }
+ parsed.add(value);
+ }
+ }
+ return parsed;
+ }
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index d4625e9..5f2ac4f 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -273,7 +273,8 @@
// Add in all the apps for every user/profile.
for (UserInfo profile : users) {
- List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
+ List<PackageInfo> pi =
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_DISABLED_COMPONENTS, profile.id);
for (int j = 0; j < pi.size(); j++) {
if (pi.get(j).applicationInfo != null) {
uids.add(pi.get(j).applicationInfo.uid);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 21fea1c..e18eee2 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -81,6 +81,7 @@
using android::hardware::Void;
using android::hardware::hidl_vec;
using android::hardware::hidl_death_recipient;
+using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::V1_0::GnssLocationFlags;
@@ -91,7 +92,6 @@
using android::hardware::gnss::V1_0::IAGnssRilCallback;
using android::hardware::gnss::V1_0::IGnssBatching;
using android::hardware::gnss::V1_0::IGnssBatchingCallback;
-using android::hardware::gnss::V1_0::IGnssConfiguration;
using android::hardware::gnss::V1_0::IGnssDebug;
using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
using android::hardware::gnss::V1_0::IGnssGeofencing;
@@ -108,6 +108,8 @@
using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
+using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
+using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
@@ -137,7 +139,8 @@
sp<IAGnss> agnssIface = nullptr;
sp<IGnssBatching> gnssBatchingIface = nullptr;
sp<IGnssDebug> gnssDebugIface = nullptr;
-sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
+sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
+sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
@@ -1098,13 +1101,11 @@
* Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
* follow.
*/
- Return<void> gnssLocationBatchCb(
- const ::android::hardware::hidl_vec<GnssLocation> & locations)
+ Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations)
override;
};
-Return<void> GnssBatchingCallback::gnssLocationBatchCb(
- const ::android::hardware::hidl_vec<GnssLocation> & locations) {
+Return<void> GnssBatchingCallback::gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations) {
JNIEnv* env = getJniEnv();
jobjectArray jLocations = env->NewObjectArray(locations.size(),
@@ -1257,11 +1258,21 @@
gnssNiIface = gnssNi;
}
- auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
- if (!gnssConfiguration.isOk()) {
- ALOGD("Unable to get a handle to GnssConfiguration");
+ if (gnssHal_V1_1 != nullptr) {
+ auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
+ if (!gnssConfiguration.isOk()) {
+ ALOGD("Unable to get a handle to GnssConfiguration");
+ } else {
+ gnssConfigurationIface_V1_1 = gnssConfiguration;
+ gnssConfigurationIface = gnssConfigurationIface_V1_1;
+ }
} else {
- gnssConfigurationIface = gnssConfiguration;
+ auto gnssConfiguration_V1_0 = gnssHal->getExtensionGnssConfiguration();
+ if (!gnssConfiguration_V1_0.isOk()) {
+ ALOGD("Unable to get a handle to GnssConfiguration");
+ } else {
+ gnssConfigurationIface = gnssConfiguration_V1_0;
+ }
}
auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
@@ -1997,6 +2008,48 @@
}
}
+static jboolean android_location_GnssLocationProvider_set_satellite_blacklist(
+ JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
+ if (gnssConfigurationIface_V1_1 == nullptr) {
+ ALOGI("No GNSS Satellite Blacklist interface available");
+ return JNI_FALSE;
+ }
+
+ jint *constellation_array = env->GetIntArrayElements(constellations, 0);
+ if (NULL == constellation_array) {
+ ALOGI("GetIntArrayElements returns NULL.");
+ return JNI_FALSE;
+ }
+ jsize length = env->GetArrayLength(constellations);
+
+ jint *sv_id_array = env->GetIntArrayElements(sv_ids, 0);
+ if (NULL == sv_id_array) {
+ ALOGI("GetIntArrayElements returns NULL.");
+ return JNI_FALSE;
+ }
+
+ if (length != env->GetArrayLength(sv_ids)) {
+ ALOGI("Lengths of constellations and sv_ids are inconsistent.");
+ return JNI_FALSE;
+ }
+
+ hidl_vec<IGnssConfiguration_V1_1::BlacklistedSource> sources;
+ sources.resize(length);
+
+ for (int i = 0; i < length; i++) {
+ sources[i].constellation = static_cast<GnssConstellationType>(constellation_array[i]);
+ sources[i].svid = sv_id_array[i];
+ }
+
+ auto result = gnssConfigurationIface_V1_1->setBlacklist(sources);
+ if (result.isOk()) {
+ return result;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+
static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return 0; // batching not supported, size = 0
@@ -2185,6 +2238,9 @@
{"native_set_emergency_supl_pdn",
"(I)Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
+ {"native_set_satellite_blacklist",
+ "([I[I)Z",
+ reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)},
{"native_get_batch_size",
"()I",
reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)},
diff --git a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java
new file mode 100644
index 0000000..d6f5446
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java
@@ -0,0 +1,130 @@
+package com.android.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Unit tests for {@link GnssSatelliteBlacklistHelper}.
+ */
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(
+ manifest = Config.NONE,
+ shadows = {
+ },
+ sdk = 27
+)
+@SystemLoaderPackages({"com.android.server.location"})
+@Presubmit
+public class GnssSatelliteBlacklistHelperTest {
+
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ @Mock
+ private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = mContext.getContentResolver();
+ new GnssSatelliteBlacklistHelper(mContext, Looper.myLooper(), mCallback);
+ }
+
+ @Test
+ public void blacklistOf2Satellites_callbackIsCalled() {
+ String blacklist = "3,0,5,24";
+ updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ }
+
+ @Test
+ public void blacklistWithSpaces_callbackIsCalled() {
+ String blacklist = "3, 11";
+ updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ }
+
+ @Test
+ public void emptyBlacklist_callbackIsCalled() {
+ String blacklist = "";
+ updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ }
+
+ @Test
+ public void blacklistWithOddNumberOfValues_callbackIsNotCalled() {
+ String blacklist = "3,0,5";
+ updateBlacklistAndNotifyContentObserver(blacklist);
+ verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ }
+
+ @Test
+ public void blacklistWithNegativeValue_callbackIsNotCalled() {
+ String blacklist = "3,-11";
+ updateBlacklistAndNotifyContentObserver(blacklist);
+ verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ }
+
+ @Test
+ public void blacklistWithNonDigitCharacter_callbackIsNotCalled() {
+ String blacklist = "3,1a,5,11";
+ updateBlacklistAndNotifyContentObserver(blacklist);
+ verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ }
+
+ private void updateBlacklistAndNotifyContentObserver(String blacklist) {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GNSS_SATELLITE_BLACKLIST, blacklist);
+ notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLACKLIST);
+ }
+
+ private void updateBlacklistAndVerifyCallbackIsCalled(String blacklist) {
+ updateBlacklistAndNotifyContentObserver(blacklist);
+
+ ArgumentCaptor<int[]> constellationsCaptor = ArgumentCaptor.forClass(int[].class);
+ ArgumentCaptor<int[]> svIdsCaptor = ArgumentCaptor.forClass(int[].class);
+ verify(mCallback).onUpdateSatelliteBlacklist(constellationsCaptor.capture(),
+ svIdsCaptor.capture());
+
+ int[] constellations = constellationsCaptor.getValue();
+ int[] svIds = svIdsCaptor.getValue();
+ List<Integer> values = GnssSatelliteBlacklistHelper.parseSatelliteBlacklist(blacklist);
+ assertThat(values.size()).isEqualTo(constellations.length * 2);
+ assertThat(svIds.length).isEqualTo(constellations.length);
+ for (int i = 0; i < constellations.length; i++) {
+ assertThat(constellations[i]).isEqualTo(values.get(i * 2));
+ assertThat(svIds[i]).isEqualTo(values.get(i * 2 + 1));
+ }
+ }
+
+ private static void notifyContentObserverFor(String globalSetting) {
+ Collection<ContentObserver> contentObservers =
+ Shadows.shadowOf(RuntimeEnvironment.application.getContentResolver())
+ .getContentObservers(Settings.Global.getUriFor(globalSetting));
+ assertThat(contentObservers).isNotEmpty();
+ contentObservers.iterator().next().onChange(false /* selfChange */);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index 477558a..a14b950 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -42,6 +42,7 @@
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
import org.junit.Before;
import org.junit.Rule;
@@ -90,6 +91,8 @@
private UserController mUserController;
@Mock
private KeyguardManager mKeyguardManager;
+ @Mock
+ private PackageManagerService mPackageManager;
private ActivityStartInterceptor mInterceptor;
private ActivityInfo mAInfo = new ActivityInfo();
@@ -121,6 +124,11 @@
nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID))).
thenReturn(CONFIRM_CREDENTIALS_INTENT);
+ // Mock PackageManager
+ when(mService.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(null);
+
// Initialise activity info
mAInfo.applicationInfo = new ApplicationInfo();
mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 288411a..aa76eab 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2187,7 +2187,7 @@
sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
- sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, false);
+ sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 35682a7..f7e6840 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -206,8 +206,10 @@
}
}
- /** @hide */
- protected NetworkService() {
+ /**
+ * Default constructor.
+ */
+ public NetworkService() {
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index e8c1cb1..4ca5ce3 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -429,8 +429,10 @@
}
}
- /** @hide */
- protected DataService() {
+ /**
+ * Default constructor.
+ */
+ public DataService() {
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index a946e50..13210e8 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -260,12 +260,14 @@
IpSecManager.IpSecTunnelInterface tunnelIntf =
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
- tunnelIntf.addAddress(VTI_INNER_ADDRESS);
+ tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
+ VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
.addAddressToTunnelInterface(
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
- tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
+ tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
+ VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
.addAddressToTunnelInterface(
eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 2f7b50d..b333126 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -143,7 +143,7 @@
WifiConfiguration getWifiApConfiguration();
- void setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
+ boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
Messenger getWifiServiceMessenger(String packageName);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 433285b..9c6c8a9 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2141,7 +2141,8 @@
}
/**
- * Sets the Wi-Fi AP Configuration.
+ * Sets the Wi-Fi AP Configuration. The AP configuration must either be open or
+ * WPA2 PSK networks.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide
@@ -2150,8 +2151,7 @@
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
- mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
- return true;
+ return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f3a78bd..f3ffcad 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1034,4 +1034,40 @@
verifyNoMoreInteractions(mWifiService);
}
+ /**
+ * Verify that a successful call properly returns true.
+ */
+ @Test
+ public void testSetWifiApConfigurationSuccessReturnsTrue() throws Exception {
+ WifiConfiguration apConfig = new WifiConfiguration();
+
+ when(mWifiService.setWifiApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(true);
+ assertTrue(mWifiManager.setWifiApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify that a failed call properly returns false.
+ */
+ @Test
+ public void testSetWifiApConfigurationFailureReturnsFalse() throws Exception {
+ WifiConfiguration apConfig = new WifiConfiguration();
+
+ when(mWifiService.setWifiApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(false);
+ assertFalse(mWifiManager.setWifiApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify Exceptions are rethrown when underlying calls to WifiService throw exceptions.
+ */
+ @Test
+ public void testSetWifiApConfigurationRethrowsException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService).setWifiApConfiguration(any(), any());
+
+ try {
+ mWifiManager.setWifiApConfiguration(new WifiConfiguration());
+ fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
+ } catch (SecurityException e) { }
+ }
}