Merge "FingerprintDialogView sets visibility incorrectly" into pi-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 962cbbf..656001c 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 {
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..41527f6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -319,7 +319,7 @@
// 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.
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index adc2664..dac73ef 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -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();
}
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..7b2881d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -95,11 +95,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}},
@@ -233,15 +232,14 @@
it->second->dump_report_time_sec.push_back(timeSec);
}
-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) {
@@ -492,11 +490,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;
@@ -641,12 +637,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..914d2af 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -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;
@@ -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);
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 139a407..db5d32c 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.
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..3b86d2d 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;
}
@@ -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..09daf75 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;
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..a97bc41 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"),
@@ -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"),
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/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/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/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/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/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/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/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/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());