summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--StubLibraries.bp49
-rw-r--r--api/current.txt2
-rwxr-xr-xapi/system-current.txt2
-rw-r--r--cmds/statsd/Android.bp5
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp3
-rw-r--r--cmds/statsd/src/hash.h1
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp5
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.h2
-rw-r--r--cmds/statsd/src/matchers/LogMatchingTracker.h18
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp6
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.h7
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp9
-rw-r--r--cmds/statsd/src/matchers/matcher_util.h4
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp32
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h10
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp203
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.h89
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp (renamed from cmds/statsd/src/metrics/metrics_manager_util.cpp)145
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h (renamed from cmds/statsd/src/metrics/metrics_manager_util.h)33
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.cpp4
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp28
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp556
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp69
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp145
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp382
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp708
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp16
-rw-r--r--cmds/statsd/tests/statsd_test_util.h4
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/Notification.java52
-rw-r--r--core/java/android/app/backup/BackupAgent.java47
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneCapabilities.java33
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneConfiguration.java35
-rw-r--r--core/java/android/app/usage/UsageEvents.java2
-rw-r--r--core/java/android/view/accessibility/IWindowMagnificationConnection.aidl8
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java7
-rw-r--r--core/proto/android/app/tvsettings_enums.proto6
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java20
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java49
-rw-r--r--non-updatable-api/current.txt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java272
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java363
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java2
-rw-r--r--services/Android.bp4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java15
-rw-r--r--services/core/java/com/android/server/VibratorService.java57
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java89
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java23
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java10
-rw-r--r--services/core/java/com/android/server/am/UserController.java19
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java76
-rw-r--r--services/core/java/com/android/server/infra/AbstractMasterSystemService.java2
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java23
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java26
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java11
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java39
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java179
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java20
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java3
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java1
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java7
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java6
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java134
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java2
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp240
-rw-r--r--services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt5
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java512
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java76
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java4
-rw-r--r--wifi/api/system-current.txt2
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java26
99 files changed, 3862 insertions, 1878 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 0fe34fb650eb..2bd5aee0cd24 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -311,15 +311,6 @@ java_defaults {
compile_dex: true,
}
-java_defaults {
- name: "android_stubs_dists_default",
- dist: {
- targets: ["sdk", "win_sdk"],
- tag: ".jar",
- dest: "android.jar",
- },
-}
-
java_library_static {
name: "android_monolith_stubs_current",
srcs: [ ":api-stubs-docs" ],
@@ -355,21 +346,7 @@ java_library_static {
name: "android_system_monolith_stubs_current",
srcs: [ ":system-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: [
- "android_defaults_stubs_current",
- "android_stubs_dists_default",
- ],
- dist: {
- dir: "apistubs/android/system",
- },
- dists: [
- {
- // Legacy dist path
- targets: ["sdk", "win_sdk"],
- tag: ".jar",
- dest: "android_system.jar",
- },
- ],
+ defaults: ["android_defaults_stubs_current"],
}
java_library_static {
@@ -401,34 +378,14 @@ java_library_static {
name: "android_test_stubs_current",
srcs: [ ":test-api-stubs-docs" ],
static_libs: [ "private-stub-annotations-jar" ],
- defaults: [
- "android_defaults_stubs_current",
- "android_stubs_dists_default",
- ],
- dist: {
- dir: "apistubs/android/test",
- },
- dists: [
- {
- // Legacy dist path
- targets: ["sdk", "win_sdk"],
- tag: ".jar",
- dest: "android_test.jar",
- },
- ],
+ defaults: ["android_defaults_stubs_current"],
}
java_library_static {
name: "android_module_lib_stubs_current",
srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
- defaults: [
- "android_defaults_stubs_current",
- "android_stubs_dists_default",
- ],
+ defaults: ["android_defaults_stubs_current"],
libs: ["sdk_system_29_android"],
- dist: {
- dir: "apistubs/android/module-lib",
- },
}
java_library_static {
diff --git a/api/current.txt b/api/current.txt
index 17fbb55d2f91..69700f3b0a60 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5596,6 +5596,7 @@ package android.app {
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public int getSemanticAction();
+ method public boolean isAuthenticationRequired();
method public boolean isContextual();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
@@ -5625,6 +5626,7 @@ package android.app {
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+ method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 94474277666d..b011e9af40a0 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7141,6 +7141,8 @@ package android.net.wifi {
field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
+ field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3
+ field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2
field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 1579715727ac..7c419519a558 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -85,8 +85,9 @@ cc_defaults {
"src/metrics/EventMetricProducer.cpp",
"src/metrics/GaugeMetricProducer.cpp",
"src/metrics/MetricProducer.cpp",
- "src/metrics/metrics_manager_util.cpp",
"src/metrics/MetricsManager.cpp",
+ "src/metrics/parsing_utils/config_update_utils.cpp",
+ "src/metrics/parsing_utils/metrics_manager_util.cpp",
"src/metrics/ValueMetricProducer.cpp",
"src/packages/UidMap.cpp",
"src/shell/shell_config.proto",
@@ -322,6 +323,8 @@ cc_test {
"tests/metrics/metrics_test_helper.cpp",
"tests/metrics/OringDurationTracker_test.cpp",
"tests/metrics/ValueMetricProducer_test.cpp",
+ "tests/metrics/parsing_utils/config_update_utils_test.cpp",
+ "tests/metrics/parsing_utils/metrics_manager_util_test.cpp",
"tests/MetricsManager_test.cpp",
"tests/shell/ShellSubscriber_test.cpp",
"tests/state/StateTracker_test.cpp",
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 6327490b0b71..7bee4e2d1a36 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -546,7 +546,8 @@ void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const C
}
} else {
// Preserve the existing MetricsManager, update necessary components and metadata in place.
- configValid = it->second->updateConfig(timestampNs, config);
+ configValid = it->second->updateConfig(config, mTimeBaseNs, timestampNs,
+ mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
if (configValid) {
// TODO(b/162323476): refresh TTL, ensure init() is handled properly.
mUidMap->OnConfigUpdated(key);
diff --git a/cmds/statsd/src/hash.h b/cmds/statsd/src/hash.h
index cfe869f60202..bd6b0cd47eaf 100644
--- a/cmds/statsd/src/hash.h
+++ b/cmds/statsd/src/hash.h
@@ -22,6 +22,7 @@ namespace android {
namespace os {
namespace statsd {
+// Uses murmur2 hashing algorithm.
extern uint32_t Hash32(const char *data, size_t n, uint32_t seed);
extern uint64_t Hash64(const char* data, size_t n, uint64_t seed);
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index b94a9572113e..60bcc26f0873 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -27,8 +27,9 @@ using std::set;
using std::unordered_map;
using std::vector;
-CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index)
- : LogMatchingTracker(id, index) {
+CombinationLogMatchingTracker::CombinationLogMatchingTracker(const int64_t& id, const int index,
+ const uint64_t protoHash)
+ : LogMatchingTracker(id, index, protoHash) {
}
CombinationLogMatchingTracker::~CombinationLogMatchingTracker() {
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 55bc46059fc1..6b8a7fb19cf0 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -28,7 +28,7 @@ namespace statsd {
// Represents a AtomMatcher_Combination in the StatsdConfig.
class CombinationLogMatchingTracker : public virtual LogMatchingTracker {
public:
- CombinationLogMatchingTracker(const int64_t& id, const int index);
+ CombinationLogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash);
bool init(const std::vector<AtomMatcher>& allLogMatchers,
const std::vector<sp<LogMatchingTracker>>& allTrackers,
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index 88ab4e6f683a..49a41add4560 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -33,8 +33,8 @@ namespace statsd {
class LogMatchingTracker : public virtual RefBase {
public:
- LogMatchingTracker(const int64_t& id, const int index)
- : mId(id), mIndex(index), mInitialized(false){};
+ LogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash)
+ : mId(id), mIndex(index), mInitialized(false), mProtoHash(protoHash){};
virtual ~LogMatchingTracker(){};
@@ -69,10 +69,14 @@ public:
return mAtomIds;
}
- const int64_t& getId() const {
+ int64_t getId() const {
return mId;
}
+ uint64_t getProtoHash() const {
+ return mProtoHash;
+ }
+
protected:
// Name of this matching. We don't really need the name, but it makes log message easy to debug.
const int64_t mId;
@@ -87,6 +91,14 @@ protected:
// return kNotMatched when we receive an event with an id not in the list. This is especially
// useful when we have a complex CombinationLogMatcherTracker.
std::set<int> mAtomIds;
+
+ // Hash of the AtomMatcher's proto bytes from StatsdConfig.
+ // Used to determine if the definition of this matcher has changed across a config update.
+ const uint64_t mProtoHash;
+
+ FRIEND_TEST(MetricsManagerTest, TestCreateLogTrackerSimple);
+ FRIEND_TEST(MetricsManagerTest, TestCreateLogTrackerCombination);
+ FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers);
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 082daf5a1916..ff47d35b36cc 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -26,11 +26,11 @@ namespace statsd {
using std::unordered_map;
using std::vector;
-
SimpleLogMatchingTracker::SimpleLogMatchingTracker(const int64_t& id, const int index,
+ const uint64_t protoHash,
const SimpleAtomMatcher& matcher,
- const UidMap& uidMap)
- : LogMatchingTracker(id, index), mMatcher(matcher), mUidMap(uidMap) {
+ const sp<UidMap>& uidMap)
+ : LogMatchingTracker(id, index, protoHash), mMatcher(matcher), mUidMap(uidMap) {
if (!matcher.has_atom_id()) {
mInitialized = false;
} else {
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index a0f6a888bd44..e58e01252ade 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -29,9 +29,8 @@ namespace statsd {
class SimpleLogMatchingTracker : public virtual LogMatchingTracker {
public:
- SimpleLogMatchingTracker(const int64_t& id, const int index,
- const SimpleAtomMatcher& matcher,
- const UidMap& uidMap);
+ SimpleLogMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash,
+ const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap);
~SimpleLogMatchingTracker();
@@ -46,7 +45,7 @@ public:
private:
const SimpleAtomMatcher mMatcher;
- const UidMap& mUidMap;
+ const sp<UidMap> mUidMap;
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 2b4c6a3cbf1e..e6d91223308d 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -81,14 +81,15 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera
return matched;
}
-bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const string& str_match) {
+bool tryMatchString(const sp<UidMap>& uidMap, const FieldValue& fieldValue,
+ const string& str_match) {
if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) {
int uid = fieldValue.mValue.int_value;
auto aidIt = UidMap::sAidToUidMapping.find(str_match);
if (aidIt != UidMap::sAidToUidMapping.end()) {
return ((int)aidIt->second) == uid;
}
- std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/);
+ std::set<string> packageNames = uidMap->getAppNamesFromUid(uid, true /* normalize*/);
return packageNames.find(str_match) != packageNames.end();
} else if (fieldValue.mValue.getType() == STRING) {
return fieldValue.mValue.str_value == str_match;
@@ -96,7 +97,7 @@ bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const st
return false;
}
-bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
+bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher,
const vector<FieldValue>& values, int start, int end, int depth) {
if (depth > 2) {
ALOGE("Depth > 3 not supported");
@@ -353,7 +354,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
}
}
-bool matchesSimple(const UidMap& uidMap, const SimpleAtomMatcher& simpleMatcher,
+bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
const LogEvent& event) {
if (event.GetTagId() != simpleMatcher.atom_id()) {
return false;
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
index 1ab3e87b5fed..130b6068bd19 100644
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -36,8 +36,8 @@ enum MatchingState {
bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
const std::vector<MatchingState>& matcherResults);
-bool matchesSimple(const UidMap& uidMap,
- const SimpleAtomMatcher& simpleMatcher, const LogEvent& wrapper);
+bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
+ const LogEvent& wrapper);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 189d8117ae55..2c3deca40fa0 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -26,7 +26,8 @@
#include "guardrail/StatsdStats.h"
#include "matchers/CombinationLogMatchingTracker.h"
#include "matchers/SimpleLogMatchingTracker.h"
-#include "metrics_manager_util.h"
+#include "parsing_utils/config_update_utils.h"
+#include "parsing_utils/metrics_manager_util.h"
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
@@ -76,13 +77,14 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
// Init the ttl end timestamp.
refreshTtl(timeBaseNs);
- mConfigValid = initStatsdConfig(
- key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
- mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
- mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
- mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
- mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds);
+ mConfigValid =
+ initStatsdConfig(key, config, uidMap, pullerManager, anomalyAlarmMonitor,
+ periodicAlarmMonitor, timeBaseNs, currentTimeNs, mTagIds,
+ mAllAtomMatchers, mLogTrackerMap, mAllConditionTrackers,
+ mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
+ mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
+ mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
+ mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
mVersionStringsInReport = config.version_strings_in_metric_report();
@@ -195,7 +197,19 @@ MetricsManager::~MetricsManager() {
VLOG("~MetricsManager()");
}
-bool MetricsManager::updateConfig(const int64_t currentTimeNs, const StatsdConfig& config) {
+bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
+ const int64_t currentTimeNs,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor) {
+ vector<sp<LogMatchingTracker>> newAtomMatchers;
+ unordered_map<int64_t, int> newLogTrackerMap;
+ mTagIds.clear();
+ mConfigValid =
+ updateStatsdConfig(mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor,
+ periodicAlarmMonitor, timeBaseNs, currentTimeNs, mAllAtomMatchers,
+ mLogTrackerMap, mTagIds, newAtomMatchers, newLogTrackerMap);
+ mAllAtomMatchers = newAtomMatchers;
+ mLogTrackerMap = newLogTrackerMap;
return mConfigValid;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 042de29e173d..6f9a23362033 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,7 +46,9 @@ public:
virtual ~MetricsManager();
- bool updateConfig(const int64_t currentTimeNs, const StatsdConfig& config);
+ bool updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
+ const int64_t currentTimeNs, const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor);
// Return whether the configuration is valid.
bool isConfigValid() const;
@@ -237,6 +239,12 @@ private:
// Hold all periodic alarm trackers.
std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers;
+ // To make updating configs faster, we map the id of a LogMatchingTracker, MetricProducer, and
+ // ConditionTracker to its index in the corresponding vector.
+
+ // Maps the id of an atom matcher to its index in mAllAtomMatchers.
+ std::unordered_map<int64_t, int> mLogTrackerMap;
+
// To make the log processing more efficient, we want to do as much filtering as possible
// before we go into individual trackers and conditions to match.
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
new file mode 100644
index 000000000000..562e29124187
--- /dev/null
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+
+#include "config_update_utils.h"
+
+#include "external/StatsPullerManager.h"
+#include "hash.h"
+#include "metrics_manager_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Recursive function to determine if a matcher needs to be updated. Populates matcherToUpdate.
+// Returns whether the function was successful or not.
+bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx,
+ const unordered_map<int64_t, int>& oldLogTrackerMap,
+ const vector<sp<LogMatchingTracker>>& oldAtomMatchers,
+ const unordered_map<int64_t, int>& newLogTrackerMap,
+ vector<UpdateStatus>& matchersToUpdate,
+ vector<bool>& cycleTracker) {
+ // Have already examined this matcher.
+ if (matchersToUpdate[matcherIdx] != UPDATE_UNKNOWN) {
+ return true;
+ }
+
+ const AtomMatcher& matcher = config.atom_matcher(matcherIdx);
+ int64_t id = matcher.id();
+ // Check if new matcher.
+ const auto& oldLogTrackerIt = oldLogTrackerMap.find(id);
+ if (oldLogTrackerIt == oldLogTrackerMap.end()) {
+ matchersToUpdate[matcherIdx] = UPDATE_REPLACE;
+ return true;
+ }
+
+ // This is an existing matcher. Check if it has changed.
+ string serializedMatcher;
+ if (!matcher.SerializeToString(&serializedMatcher)) {
+ ALOGE("Unable to serialize matcher %lld", (long long)id);
+ return false;
+ }
+ uint64_t newProtoHash = Hash64(serializedMatcher);
+ if (newProtoHash != oldAtomMatchers[oldLogTrackerIt->second]->getProtoHash()) {
+ matchersToUpdate[matcherIdx] = UPDATE_REPLACE;
+ return true;
+ }
+
+ switch (matcher.contents_case()) {
+ case AtomMatcher::ContentsCase::kSimpleAtomMatcher: {
+ matchersToUpdate[matcherIdx] = UPDATE_PRESERVE;
+ return true;
+ }
+ case AtomMatcher::ContentsCase::kCombination: {
+ // Recurse to check if children have changed.
+ cycleTracker[matcherIdx] = true;
+ UpdateStatus status = UPDATE_PRESERVE;
+ for (const int64_t childMatcherId : matcher.combination().matcher()) {
+ const auto& childIt = newLogTrackerMap.find(childMatcherId);
+ if (childIt == newLogTrackerMap.end()) {
+ ALOGW("Matcher %lld not found in the config", (long long)childMatcherId);
+ return false;
+ }
+ const int childIdx = childIt->second;
+ if (cycleTracker[childIdx]) {
+ ALOGE("Cycle detected in matcher config");
+ return false;
+ }
+ if (!determineMatcherUpdateStatus(config, childIdx, oldLogTrackerMap,
+ oldAtomMatchers, newLogTrackerMap,
+ matchersToUpdate, cycleTracker)) {
+ return false;
+ }
+
+ if (matchersToUpdate[childIdx] == UPDATE_REPLACE) {
+ status = UPDATE_REPLACE;
+ break;
+ }
+ }
+ matchersToUpdate[matcherIdx] = status;
+ cycleTracker[matcherIdx] = false;
+ return true;
+ }
+ default: {
+ ALOGE("Matcher \"%lld\" malformed", (long long)id);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool updateLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const unordered_map<int64_t, int>& oldLogTrackerMap,
+ const vector<sp<LogMatchingTracker>>& oldAtomMatchers, set<int>& allTagIds,
+ unordered_map<int64_t, int>& newLogTrackerMap,
+ vector<sp<LogMatchingTracker>>& newAtomMatchers) {
+ const int atomMatcherCount = config.atom_matcher_size();
+
+ vector<AtomMatcher> matcherProtos;
+ matcherProtos.reserve(atomMatcherCount);
+ newAtomMatchers.reserve(atomMatcherCount);
+
+ // Maps matcher id to their position in the config. For fast lookup of dependencies.
+ for (int i = 0; i < atomMatcherCount; i++) {
+ const AtomMatcher& matcher = config.atom_matcher(i);
+ if (newLogTrackerMap.find(matcher.id()) != newLogTrackerMap.end()) {
+ ALOGE("Duplicate atom matcher found for id %lld", (long long)matcher.id());
+ return false;
+ }
+ newLogTrackerMap[matcher.id()] = i;
+ matcherProtos.push_back(matcher);
+ }
+
+ // For combination matchers, we need to determine if any children need to be updated.
+ vector<UpdateStatus> matchersToUpdate(atomMatcherCount, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(atomMatcherCount, false);
+ for (int i = 0; i < atomMatcherCount; i++) {
+ if (!determineMatcherUpdateStatus(config, i, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker)) {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < atomMatcherCount; i++) {
+ const AtomMatcher& matcher = config.atom_matcher(i);
+ const int64_t id = matcher.id();
+ switch (matchersToUpdate[i]) {
+ case UPDATE_PRESERVE: {
+ const auto& oldLogTrackerIt = oldLogTrackerMap.find(id);
+ if (oldLogTrackerIt == oldLogTrackerMap.end()) {
+ ALOGE("Could not find AtomMatcher %lld in the previous config, but expected it "
+ "to be there",
+ (long long)id);
+ return false;
+ }
+ const int oldIndex = oldLogTrackerIt->second;
+ newAtomMatchers.push_back(oldAtomMatchers[oldIndex]);
+ break;
+ }
+ case UPDATE_REPLACE: {
+ sp<LogMatchingTracker> tracker = createLogTracker(matcher, i, uidMap);
+ if (tracker == nullptr) {
+ return false;
+ }
+ newAtomMatchers.push_back(tracker);
+ break;
+ }
+ default: {
+ ALOGE("Matcher \"%lld\" update state is unknown. This should never happen",
+ (long long)id);
+ return false;
+ }
+ }
+ }
+
+ std::fill(cycleTracker.begin(), cycleTracker.end(), false);
+ for (auto& matcher : newAtomMatchers) {
+ if (!matcher->init(matcherProtos, newAtomMatchers, newLogTrackerMap, cycleTracker)) {
+ return false;
+ }
+ // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
+ const set<int>& tagIds = matcher->getAtomIds();
+ allTagIds.insert(tagIds.begin(), tagIds.end());
+ }
+
+ return true;
+}
+
+bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const sp<StatsPullerManager>& pullerManager,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
+ const int64_t currentTimeNs,
+ const vector<sp<LogMatchingTracker>>& oldAtomMatchers,
+ const unordered_map<int64_t, int>& oldLogTrackerMap, set<int>& allTagIds,
+ vector<sp<LogMatchingTracker>>& newAtomMatchers,
+ unordered_map<int64_t, int>& newLogTrackerMap) {
+ if (!updateLogTrackers(config, uidMap, oldLogTrackerMap, oldAtomMatchers, allTagIds,
+ newLogTrackerMap, newAtomMatchers)) {
+ ALOGE("updateLogMatchingTrackers failed");
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
new file mode 100644
index 000000000000..951ab03cee47
--- /dev/null
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "anomaly/AlarmMonitor.h"
+#include "external/StatsPullerManager.h"
+#include "matchers/LogMatchingTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Helper functions for MetricsManager to update itself from a new StatsdConfig.
+// *Note*: only updateStatsdConfig() should be called from outside this file.
+// All other functions are intermediate steps, created to make unit testing easier.
+
+// Possible update states for a component. PRESERVE means we should keep the existing one.
+// REPLACE means we should create a new one, either because it didn't exist or it changed.
+enum UpdateStatus {
+ UPDATE_UNKNOWN = 0,
+ UPDATE_PRESERVE = 1,
+ UPDATE_REPLACE = 2,
+};
+
+// Recursive function to determine if a matcher needs to be updated.
+// input:
+// [config]: the input StatsdConfig
+// [matcherIdx]: the index of the current matcher to be updated
+// [newLogTrackerMap]: matcher id to index mapping in the input StatsdConfig
+// [oldLogTrackerMap]: matcher id to index mapping in the existing MetricsManager
+// [oldAtomMatchers]: stores the existing LogMatchingTrackers
+// output:
+// [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will
+// be updated from UPDATE_UNKNOWN after this call.
+// [cycleTracker]: intermediate param used during recursion.
+bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx,
+ const unordered_map<int64_t, int>& oldLogTrackerMap,
+ const vector<sp<LogMatchingTracker>>& oldAtomMatchers,
+ const unordered_map<int64_t, int>& newLogTrackerMap,
+ vector<UpdateStatus>& matchersToUpdate,
+ vector<bool>& cycleTracker);
+
+// Updates the LogMatchingTrackers.
+// input:
+// [config]: the input StatsdConfig
+// [oldLogTrackerMap]: existing matcher id to index mapping
+// [oldAtomMatchers]: stores the existing LogMatchingTrackers
+// output:
+// [allTagIds]: contains the set of all interesting tag ids to this config.
+// [newLogTrackerMap]: new matcher id to index mapping
+// [newAtomMatchers]: stores the new LogMatchingTrackers
+bool updateLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const unordered_map<int64_t, int>& oldLogTrackerMap,
+ const vector<sp<LogMatchingTracker>>& oldAtomMatchers, set<int>& allTagIds,
+ unordered_map<int64_t, int>& newLogTrackerMap,
+ vector<sp<LogMatchingTracker>>& newAtomMatchers);
+
+// Updates the existing MetricsManager from a new StatsdConfig.
+// Parameters are the members of MetricsManager. See MetricsManager for declaration.
+bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
+ const sp<StatsPullerManager>& pullerManager,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
+ const int64_t currentTimeNs,
+ const std::vector<sp<LogMatchingTracker>>& oldAtomMatchers,
+ const unordered_map<int64_t, int>& oldLogTrackerMap,
+ std::set<int>& allTagIds,
+ std::vector<sp<LogMatchingTracker>>& newAtomMatchers,
+ unordered_map<int64_t, int>& newLogTrackerMap);
+
+} // namespace statsd
+} // namespace os
+} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index 8917c36bb608..52ef95d19cdc 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -22,10 +22,10 @@
#include <inttypes.h>
#include "FieldValue.h"
-#include "MetricProducer.h"
#include "condition/CombinationConditionTracker.h"
#include "condition/SimpleConditionTracker.h"
#include "external/StatsPullerManager.h"
+#include "hash.h"
#include "matchers/CombinationLogMatchingTracker.h"
#include "matchers/EventMatcherWizard.h"
#include "matchers/SimpleLogMatchingTracker.h"
@@ -33,6 +33,7 @@
#include "metrics/DurationMetricProducer.h"
#include "metrics/EventMetricProducer.h"
#include "metrics/GaugeMetricProducer.h"
+#include "metrics/MetricProducer.h"
#include "metrics/ValueMetricProducer.h"
#include "state/StateManager.h"
#include "stats_util.h"
@@ -61,6 +62,28 @@ bool hasLeafNode(const FieldMatcher& matcher) {
} // namespace
+sp<LogMatchingTracker> createLogTracker(const AtomMatcher& logMatcher, const int index,
+ const sp<UidMap>& uidMap) {
+ string serializedMatcher;
+ if (!logMatcher.SerializeToString(&serializedMatcher)) {
+ ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id());
+ return nullptr;
+ }
+ uint64_t protoHash = Hash64(serializedMatcher);
+ switch (logMatcher.contents_case()) {
+ case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
+ return new SimpleLogMatchingTracker(logMatcher.id(), index, protoHash,
+ logMatcher.simple_atom_matcher(), uidMap);
+ break;
+ case AtomMatcher::ContentsCase::kCombination:
+ return new CombinationLogMatchingTracker(logMatcher.id(), index, protoHash);
+ break;
+ default:
+ ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
+ return nullptr;
+ }
+}
+
bool handleMetricWithLogTrackers(const int64_t what, const int metricIndex,
const bool usedForDimension,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
@@ -184,9 +207,7 @@ bool handleMetricWithStateLink(const FieldMatcher& stateMatcher,
// to provide the producer with state about its activators and deactivators.
// Returns false if there are errors.
bool handleMetricActivation(
- const StatsdConfig& config,
- const int64_t metricId,
- const int metricIndex,
+ const StatsdConfig& config, const int64_t metricId, const int metricIndex,
const unordered_map<int64_t, int>& metricToActivationMap,
const unordered_map<int64_t, int>& logTrackerMap,
unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
@@ -210,10 +231,11 @@ bool handleMetricActivation(
return false;
}
- ActivationType activationType = (activation.has_activation_type()) ?
- activation.activation_type() : metricActivation.activation_type();
- std::shared_ptr<Activation> activationWrapper = std::make_shared<Activation>(
- activationType, activation.ttl_seconds() * NS_PER_SEC);
+ ActivationType activationType = (activation.has_activation_type())
+ ? activation.activation_type()
+ : metricActivation.activation_type();
+ std::shared_ptr<Activation> activationWrapper =
+ std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC);
int atomMatcherIndex = itr->second;
activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
@@ -235,7 +257,7 @@ bool handleMetricActivation(
return true;
}
-bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
+bool initLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
vector<AtomMatcher> matcherConfigs;
@@ -245,22 +267,12 @@ bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
for (int i = 0; i < atomMatcherCount; i++) {
const AtomMatcher& logMatcher = config.atom_matcher(i);
-
int index = allAtomMatchers.size();
- switch (logMatcher.contents_case()) {
- case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
- allAtomMatchers.push_back(new SimpleLogMatchingTracker(
- logMatcher.id(), index, logMatcher.simple_atom_matcher(), uidMap));
- break;
- case AtomMatcher::ContentsCase::kCombination:
- allAtomMatchers.push_back(
- new CombinationLogMatchingTracker(logMatcher.id(), index));
- break;
- default:
- ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
- return false;
- // continue;
+ sp<LogMatchingTracker> tracker = createLogTracker(logMatcher, index, uidMap);
+ if (tracker == nullptr) {
+ return false;
}
+ allAtomMatchers.push_back(tracker);
if (logTrackerMap.find(logMatcher.id()) != logTrackerMap.end()) {
ALOGE("Duplicate AtomMatcher found!");
return false;
@@ -383,7 +395,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
const MetricActivation& metricActivation = config.metric_activation(i);
int64_t metricId = metricActivation.metric_id();
if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
- ALOGE("Metric %lld has multiple MetricActivations", (long long) metricId);
+ ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId);
return false;
}
metricToActivationMap.insert({metricId, i});
@@ -402,9 +414,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
- metric.has_dimensions_in_what(),
- allAtomMatchers, logTrackerMap, trackerToMetricMap,
- trackerIndex)) {
+ metric.has_dimensions_in_what(), allAtomMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
@@ -438,10 +449,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
- bool success = handleMetricActivation(config, metric.id(), metricIndex,
- metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
- eventDeactivationMap);
+ bool success = handleMetricActivation(
+ config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap);
if (!success) return false;
sp<MetricProducer> countProducer =
@@ -544,10 +555,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
- bool success = handleMetricActivation(config, metric.id(), metricIndex,
- metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
- eventDeactivationMap);
+ bool success = handleMetricActivation(
+ config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap);
if (!success) return false;
sp<MetricProducer> durationMetric = new DurationMetricProducer(
@@ -591,10 +602,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
- bool success = handleMetricActivation(config, metric.id(), metricIndex,
- metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
- eventDeactivationMap);
+ bool success = handleMetricActivation(
+ config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap);
if (!success) return false;
sp<MetricProducer> eventMetric =
@@ -626,9 +637,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
- metric.has_dimensions_in_what(),
- allAtomMatchers, logTrackerMap, trackerToMetricMap,
- trackerIndex)) {
+ metric.has_dimensions_in_what(), allAtomMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
@@ -718,9 +728,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
metricMap.insert({metric.id(), metricIndex});
int trackerIndex;
if (!handleMetricWithLogTrackers(metric.what(), metricIndex,
- metric.has_dimensions_in_what(),
- allAtomMatchers, logTrackerMap, trackerToMetricMap,
- trackerIndex)) {
+ metric.has_dimensions_in_what(), allAtomMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
@@ -775,10 +784,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
- bool success = handleMetricActivation(config, metric.id(), metricIndex,
- metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
- eventDeactivationMap);
+ bool success = handleMetricActivation(
+ config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap);
if (!success) return false;
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
@@ -813,8 +822,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
return true;
}
-bool initAlerts(const StatsdConfig& config,
- const unordered_map<int64_t, int>& metricProducerMap,
+bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap,
unordered_map<int64_t, int>& alertTrackerMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
vector<sp<MetricProducer>>& allMetricProducers,
@@ -832,8 +840,8 @@ bool initAlerts(const StatsdConfig& config,
return false;
}
if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
- ALOGW("invalid alert: threshold=%f num_buckets= %d",
- alert.trigger_if_sum_gt(), alert.num_buckets());
+ ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
+ alert.num_buckets());
return false;
}
const int metricIndex = itr->second;
@@ -853,14 +861,13 @@ bool initAlerts(const StatsdConfig& config,
}
if (subscription.subscriber_information_case() ==
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
- ALOGW("subscription \"%lld\" has no subscriber info.\"",
- (long long)subscription.id());
+ ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
return false;
}
const auto& itr = alertTrackerMap.find(subscription.rule_id());
if (itr == alertTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
- (long long)subscription.id(), (long long)subscription.rule_id());
+ (long long)subscription.id(), (long long)subscription.rule_id());
return false;
}
const int anomalyTrackerIndex = itr->second;
@@ -870,12 +877,11 @@ bool initAlerts(const StatsdConfig& config,
}
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
- const sp<AlarmMonitor>& periodicAlarmMonitor,
- const int64_t timeBaseNs, const int64_t currentTimeNs,
- vector<sp<AlarmTracker>>& allAlarmTrackers) {
+ const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
+ const int64_t currentTimeNs, vector<sp<AlarmTracker>>& allAlarmTrackers) {
unordered_map<int64_t, int> alarmTrackerMap;
int64_t startMillis = timeBaseNs / 1000 / 1000;
- int64_t currentTimeMillis = currentTimeNs / 1000 /1000;
+ int64_t currentTimeMillis = currentTimeNs / 1000 / 1000;
for (int i = 0; i < config.alarm_size(); i++) {
const Alarm& alarm = config.alarm(i);
if (alarm.offset_millis() <= 0) {
@@ -888,8 +894,7 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
}
alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
allAlarmTrackers.push_back(
- new AlarmTracker(startMillis, currentTimeMillis,
- alarm, key, periodicAlarmMonitor));
+ new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor));
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
@@ -898,14 +903,13 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
}
if (subscription.subscriber_information_case() ==
Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
- ALOGW("subscription \"%lld\" has no subscriber info.\"",
- (long long)subscription.id());
+ ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
return false;
}
const auto& itr = alarmTrackerMap.find(subscription.rule_id());
if (itr == alarmTrackerMap.end()) {
ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
- (long long)subscription.id(), (long long)subscription.rule_id());
+ (long long)subscription.id(), (long long)subscription.rule_id());
return false;
}
const int trackerIndex = itr->second;
@@ -914,12 +918,13 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
return true;
}
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
const int64_t currentTimeNs, set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
+ unordered_map<int64_t, int>& logTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
@@ -930,9 +935,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
unordered_map<int64_t, int>& alertTrackerMap,
- vector<int>& metricsWithActivation,
- std::set<int64_t>& noReportMetricIds) {
- unordered_map<int64_t, int> logTrackerMap;
+ vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> conditionTrackerMap;
vector<ConditionState> initialConditionCache;
unordered_map<int64_t, int> metricProducerMap;
@@ -969,8 +972,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initAlerts failed");
return false;
}
- if (!initAlarms(config, key, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, allPeriodicAlarmTrackers)) {
+ if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
+ allPeriodicAlarmTrackers)) {
ALOGE("initAlarms failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
index 96b5c26ff789..ed9951fd5ee6 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
@@ -20,16 +20,28 @@
#include <unordered_map>
#include <vector>
-#include "../anomaly/AlarmTracker.h"
-#include "../condition/ConditionTracker.h"
-#include "../external/StatsPullerManager.h"
-#include "../matchers/LogMatchingTracker.h"
-#include "../metrics/MetricProducer.h"
+#include "anomaly/AlarmTracker.h"
+#include "condition/ConditionTracker.h"
+#include "external/StatsPullerManager.h"
+#include "matchers/LogMatchingTracker.h"
+#include "metrics/MetricProducer.h"
namespace android {
namespace os {
namespace statsd {
+// Helper functions for creating individual config components from StatsdConfig.
+// Should only be called from metrics_manager_util and config_update_utils.
+
+// Create a LogMatchingTracker.
+// input:
+// [logMatcher]: the input AtomMatcher from the StatsdConfig
+// [index]: the index of the matcher
+// output:
+// new LogMatchingTracker, or null if the tracker is unable to be created
+sp<LogMatchingTracker> createLogTracker(const AtomMatcher& logMatcher, const int index,
+ const sp<UidMap>& uidMap);
+
// Helper functions for MetricsManager to initialize from StatsdConfig.
// *Note*: only initStatsdConfig() should be called from outside.
// All other functions are intermediate
@@ -44,8 +56,7 @@ namespace statsd {
// [logTrackerMap]: this map should contain matcher name to index mapping
// [allAtomMatchers]: should store the sp to all the LogMatchingTracker
// [allTagIds]: contains the set of all interesting tag ids to this config.
-bool initLogTrackers(const StatsdConfig& config,
- const UidMap& uidMap,
+bool initLogTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
std::unordered_map<int64_t, int>& logTrackerMap,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::set<int>& allTagIds);
@@ -97,7 +108,7 @@ bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAt
// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
bool initMetrics(
const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
- const int64_t currentTimeNs, UidMap& uidMap, const sp<StatsPullerManager>& pullerManager,
+ const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
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,
@@ -116,12 +127,13 @@ bool initMetrics(
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
const int64_t currentTimeNs, std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
+ std::unordered_map<int64_t, int>& logTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
vector<sp<AnomalyTracker>>& allAnomalyTrackers,
@@ -132,8 +144,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
std::unordered_map<int64_t, int>& alertTrackerMap,
- vector<int>& metricsWithActivation,
- std::set<int64_t>& noReportMetricIds);
+ vector<int>& metricsWithActivation, std::set<int64_t>& noReportMetricIds);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index fd883c29dba0..9d8f0c24e253 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -191,7 +191,7 @@ void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEve
mProto.clear();
int count = 0;
for (const auto& event : data) {
- if (matchesSimple(*mUidMap, matcher, *event)) {
+ if (matchesSimple(mUidMap, matcher, *event)) {
count++;
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
@@ -209,7 +209,7 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) {
mProto.clear();
for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) {
- if (matchesSimple(*mUidMap, matcher, event)) {
+ if (matchesSimple(mUidMap, matcher, event)) {
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event.ToProto(mProto);
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 6264c075426a..92cd04f37ee0 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -110,7 +110,7 @@ void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t ti
} // anonymous namespace
TEST(AtomMatcherTest, TestSimpleMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
@@ -129,7 +129,7 @@ TEST(AtomMatcherTest, TestSimpleMatcher) {
}
TEST(AtomMatcherTest, TestAttributionMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
std::vector<int> attributionUids = {1111, 2222, 3333};
std::vector<string> attributionTags = {"location1", "location2", "location3"};
@@ -204,7 +204,7 @@ TEST(AtomMatcherTest, TestAttributionMatcher) {
"pkg0");
EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
- uidMap.updateMap(
+ uidMap->updateMap(
1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("v1"), android::String16("v1"), android::String16("v2"),
android::String16("v1"), android::String16("v2")},
@@ -356,8 +356,8 @@ TEST(AtomMatcherTest, TestAttributionMatcher) {
}
TEST(AtomMatcherTest, TestUidFieldMatcher) {
- UidMap uidMap;
- uidMap.updateMap(
+ sp<UidMap> uidMap = new UidMap();
+ uidMap->updateMap(
1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("v1"), android::String16("v1"), android::String16("v2"),
android::String16("v1"), android::String16("v2")},
@@ -392,8 +392,8 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) {
}
TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
- UidMap uidMap;
- uidMap.updateMap(
+ sp<UidMap> uidMap = new UidMap();
+ uidMap->updateMap(
1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("v1"), android::String16("v1"), android::String16("v2"),
android::String16("v1"), android::String16("v2")},
@@ -453,8 +453,8 @@ TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
}
TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
- UidMap uidMap;
- uidMap.updateMap(
+ sp<UidMap> uidMap = new UidMap();
+ uidMap->updateMap(
1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
{android::String16("v1"), android::String16("v1"), android::String16("v2"),
android::String16("v1"), android::String16("v2")},
@@ -517,7 +517,7 @@ TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
}
TEST(AtomMatcherTest, TestBoolMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
auto simpleMatcher = matcher.mutable_simple_atom_matcher();
@@ -550,7 +550,7 @@ TEST(AtomMatcherTest, TestBoolMatcher) {
}
TEST(AtomMatcherTest, TestStringMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
auto simpleMatcher = matcher.mutable_simple_atom_matcher();
@@ -568,7 +568,7 @@ TEST(AtomMatcherTest, TestStringMatcher) {
}
TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
auto simpleMatcher = matcher.mutable_simple_atom_matcher();
@@ -597,7 +597,7 @@ TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
}
TEST(AtomMatcherTest, TestIntComparisonMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
auto simpleMatcher = matcher.mutable_simple_atom_matcher();
@@ -654,7 +654,7 @@ TEST(AtomMatcherTest, TestIntComparisonMatcher) {
}
TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
- UidMap uidMap;
+ sp<UidMap> uidMap = new UidMap();
// Set up the matcher
AtomMatcher matcher;
auto simpleMatcher = matcher.mutable_simple_atom_matcher();
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 6259757fe092..8dd608347064 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -28,7 +28,7 @@
#include "src/metrics/GaugeMetricProducer.h"
#include "src/metrics/MetricProducer.h"
#include "src/metrics/ValueMetricProducer.h"
-#include "src/metrics/metrics_manager_util.h"
+#include "src/metrics/parsing_utils/metrics_manager_util.h"
#include "src/state/StateManager.h"
#include "statsd_test_util.h"
@@ -48,7 +48,6 @@ namespace statsd {
namespace {
const ConfigKey kConfigKey(0, 12345);
-const long kAlertId = 3;
const long timeBaseSec = 1000;
@@ -90,287 +89,6 @@ StatsdConfig buildGoodConfig() {
metric->set_bucket(ONE_MINUTE);
metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
- config.add_no_report_metric(3);
-
- auto alert = config.add_alert();
- alert->set_id(kAlertId);
- alert->set_metric_id(3);
- alert->set_num_buckets(10);
- alert->set_refractory_period_secs(100);
- alert->set_trigger_if_sum_gt(100);
- return config;
-}
-
-StatsdConfig buildCircleMatchers() {
- StatsdConfig config;
- config.set_id(12345);
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
- SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
- simpleAtomMatcher->add_field_value_matcher()->set_field(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
- 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
- AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
- combination->set_operation(LogicalOperation::OR);
- combination->add_matcher(StringToId("SCREEN_IS_ON"));
- // Circle dependency
- combination->add_matcher(StringToId("SCREEN_ON_OR_OFF"));
-
- return config;
-}
-
-StatsdConfig buildAlertWithUnknownMetric() {
- StatsdConfig config;
- config.set_id(12345);
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
- CountMetric* metric = config.add_count_metric();
- metric->set_id(3);
- metric->set_what(StringToId("SCREEN_IS_ON"));
- metric->set_bucket(ONE_MINUTE);
- metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
- metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
- auto alert = config.add_alert();
- alert->set_id(3);
- alert->set_metric_id(2);
- alert->set_num_buckets(10);
- alert->set_refractory_period_secs(100);
- alert->set_trigger_if_sum_gt(100);
- return config;
-}
-
-StatsdConfig buildMissingMatchers() {
- StatsdConfig config;
- config.set_id(12345);
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
- SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
- simpleAtomMatcher->add_field_value_matcher()->set_field(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
- 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
- AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
- combination->set_operation(LogicalOperation::OR);
- combination->add_matcher(StringToId("SCREEN_IS_ON"));
- // undefined matcher
- combination->add_matcher(StringToId("ABC"));
-
- return config;
-}
-
-StatsdConfig buildMissingPredicate() {
- StatsdConfig config;
- config.set_id(12345);
-
- CountMetric* metric = config.add_count_metric();
- metric->set_id(3);
- metric->set_what(StringToId("SCREEN_EVENT"));
- metric->set_bucket(ONE_MINUTE);
- metric->set_condition(StringToId("SOME_CONDITION"));
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_EVENT"));
-
- SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2);
-
- return config;
-}
-
-StatsdConfig buildDimensionMetricsWithMultiTags() {
- StatsdConfig config;
- config.set_id(12345);
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("BATTERY_VERY_LOW"));
- SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2);
-
- eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW"));
- simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(3);
-
- eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("BATTERY_LOW"));
-
- AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
- combination->set_operation(LogicalOperation::OR);
- combination->add_matcher(StringToId("BATTERY_VERY_LOW"));
- combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW"));
-
- // Count process state changes, slice by uid, while SCREEN_IS_OFF
- CountMetric* metric = config.add_count_metric();
- metric->set_id(3);
- metric->set_what(StringToId("BATTERY_LOW"));
- metric->set_bucket(ONE_MINUTE);
- // This case is interesting. We want to dimension across two atoms.
- metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
- auto alert = config.add_alert();
- alert->set_id(kAlertId);
- alert->set_metric_id(3);
- alert->set_num_buckets(10);
- alert->set_refractory_period_secs(100);
- alert->set_trigger_if_sum_gt(100);
- return config;
-}
-
-StatsdConfig buildCirclePredicates() {
- StatsdConfig config;
- config.set_id(12345);
-
- AtomMatcher* eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
- SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
- simpleAtomMatcher->add_field_value_matcher()->set_field(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
- 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- eventMatcher = config.add_atom_matcher();
- eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
-
- simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
- simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
- simpleAtomMatcher->add_field_value_matcher()->set_field(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
- auto condition = config.add_predicate();
- condition->set_id(StringToId("SCREEN_IS_ON"));
- SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
- simplePredicate->set_start(StringToId("SCREEN_IS_ON"));
- simplePredicate->set_stop(StringToId("SCREEN_IS_OFF"));
-
- condition = config.add_predicate();
- condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF"));
-
- Predicate_Combination* combination = condition->mutable_combination();
- combination->set_operation(LogicalOperation::OR);
- combination->add_predicate(StringToId("SCREEN_IS_ON"));
- combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF"));
-
- return config;
-}
-
-StatsdConfig buildConfigWithDifferentPredicates() {
- StatsdConfig config;
- config.set_id(12345);
-
- auto pulledAtomMatcher =
- CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE);
- *config.add_atom_matcher() = pulledAtomMatcher;
- auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher();
- *config.add_atom_matcher() = screenOnAtomMatcher;
- auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher();
- *config.add_atom_matcher() = screenOffAtomMatcher;
- auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher();
- *config.add_atom_matcher() = batteryNoneAtomMatcher;
- auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher();
- *config.add_atom_matcher() = batteryUsbAtomMatcher;
-
- // Simple condition with InitialValue set to default (unknown).
- auto screenOnUnknownPredicate = CreateScreenIsOnPredicate();
- *config.add_predicate() = screenOnUnknownPredicate;
-
- // Simple condition with InitialValue set to false.
- auto screenOnFalsePredicate = config.add_predicate();
- screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse"));
- SimplePredicate* simpleScreenOnFalsePredicate =
- screenOnFalsePredicate->mutable_simple_predicate();
- simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id());
- simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id());
- simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
-
- // Simple condition with InitialValue set to false.
- auto onBatteryFalsePredicate = config.add_predicate();
- onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse"));
- SimplePredicate* simpleOnBatteryFalsePredicate =
- onBatteryFalsePredicate->mutable_simple_predicate();
- simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id());
- simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id());
- simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
-
- // Combination condition with both simple condition InitialValues set to false.
- auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate();
- screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse"));
- screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation(
- LogicalOperation::AND);
- addPredicateToPredicateCombination(*screenOnFalsePredicate,
- screenOnFalseOnBatteryFalsePredicate);
- addPredicateToPredicateCombination(*onBatteryFalsePredicate,
- screenOnFalseOnBatteryFalsePredicate);
-
- // Combination condition with one simple condition InitialValue set to unknown and one set to
- // false.
- auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate();
- screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse"));
- screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation(
- LogicalOperation::AND);
- addPredicateToPredicateCombination(screenOnUnknownPredicate,
- screenOnUnknownOnBatteryFalsePredicate);
- addPredicateToPredicateCombination(*onBatteryFalsePredicate,
- screenOnUnknownOnBatteryFalsePredicate);
-
- // Simple condition metric with initial value false.
- ValueMetric* metric1 = config.add_value_metric();
- metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse"));
- metric1->set_what(pulledAtomMatcher.id());
- *metric1->mutable_value_field() =
- CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
- metric1->set_bucket(FIVE_MINUTES);
- metric1->set_condition(screenOnFalsePredicate->id());
-
- // Simple condition metric with initial value unknown.
- ValueMetric* metric2 = config.add_value_metric();
- metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown"));
- metric2->set_what(pulledAtomMatcher.id());
- *metric2->mutable_value_field() =
- CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
- metric2->set_bucket(FIVE_MINUTES);
- metric2->set_condition(screenOnUnknownPredicate.id());
-
- // Combination condition metric with initial values false and false.
- ValueMetric* metric3 = config.add_value_metric();
- metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse"));
- metric3->set_what(pulledAtomMatcher.id());
- *metric3->mutable_value_field() =
- CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
- metric3->set_bucket(FIVE_MINUTES);
- metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id());
-
- // Combination condition metric with initial values unknown and false.
- ValueMetric* metric4 = config.add_value_metric();
- metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse"));
- metric4->set_what(pulledAtomMatcher.id());
- *metric4->mutable_value_field() =
- CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
- metric4->set_bucket(FIVE_MINUTES);
- metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id());
-
return config;
}
@@ -379,274 +97,6 @@ bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) {
}
} // anonymous namespace
-TEST(MetricsManagerTest, TestInitialConditions) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildConfigWithDifferentPredicates();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_TRUE(initStatsdConfig(
- kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers,
- allMetricProducers, allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
- ASSERT_EQ(4u, allMetricProducers.size());
- ASSERT_EQ(5u, allConditionTrackers.size());
-
- ConditionKey queryKey;
- vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
-
- allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
- allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
- EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
- EXPECT_EQ(ConditionState::kFalse, conditionCache[1]);
- EXPECT_EQ(ConditionState::kFalse, conditionCache[2]);
- EXPECT_EQ(ConditionState::kFalse, conditionCache[3]);
- EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]);
-
- EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition);
- EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition);
- EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition);
- EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition);
-}
-
-TEST(MetricsManagerTest, TestGoodConfig) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildGoodConfig();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
- ASSERT_EQ(1u, allMetricProducers.size());
- ASSERT_EQ(1u, allAnomalyTrackers.size());
- ASSERT_EQ(1u, noReportMetricIds.size());
- ASSERT_EQ(1u, alertTrackerMap.size());
- EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
- EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
-}
-
-TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildDimensionMetricsWithMultiTags();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildCircleMatchers();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestMissingMatchers) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildMissingMatchers();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestMissingPredicate) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildMissingPredicate();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestCirclePredicateDependency) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildCirclePredicates();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
- UidMap uidMap;
- sp<StatsPullerManager> pullerManager = new StatsPullerManager();
- sp<AlarmMonitor> anomalyAlarmMonitor;
- sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildAlertWithUnknownMetric();
- set<int> allTagIds;
- vector<sp<LogMatchingTracker>> allAtomMatchers;
- vector<sp<ConditionTracker>> allConditionTrackers;
- vector<sp<MetricProducer>> allMetricProducers;
- std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
- std::vector<sp<AlarmTracker>> allAlarmTrackers;
- unordered_map<int, std::vector<int>> conditionToMetricMap;
- unordered_map<int, std::vector<int>> trackerToMetricMap;
- unordered_map<int, std::vector<int>> trackerToConditionMap;
- unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
- unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
- unordered_map<int64_t, int> alertTrackerMap;
- vector<int> metricsWithActivation;
- std::set<int64_t> noReportMetricIds;
-
- EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
- periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
- allAtomMatchers, allConditionTrackers, allMetricProducers,
- allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap,
- activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
- alertTrackerMap, metricsWithActivation,
- noReportMetricIds));
-}
-
TEST(MetricsManagerTest, TestLogSources) {
string app1 = "app1";
set<int32_t> app1Uids = {1111, 11111};
@@ -680,7 +130,7 @@ TEST(MetricsManagerTest, TestLogSources) {
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildGoodConfig();
+ StatsdConfig config;
config.add_allowed_log_source("AID_SYSTEM");
config.add_allowed_log_source(app1);
config.add_default_pull_packages("AID_SYSTEM");
@@ -744,7 +194,7 @@ TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
sp<AlarmMonitor> anomalyAlarmMonitor;
sp<AlarmMonitor> periodicAlarmMonitor;
- StatsdConfig config = buildGoodConfig();
+ StatsdConfig config;
config.add_whitelisted_atom_ids(3);
config.add_whitelisted_atom_ids(4);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index caea42dfe032..d96ff8a1925b 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -47,7 +47,6 @@ namespace {
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
-const int64_t atomMatcherId = 678;
const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
@@ -94,11 +93,8 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
- new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<EventMatcherWizard> eventMatcherWizard =
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -127,12 +123,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -217,12 +209,8 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, logEventMatcherIndex, eventMatcherWizard,
@@ -301,12 +289,9 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
@@ -378,12 +363,8 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -428,12 +409,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
int64_t conditionChangeNs = bucketStartTimeNs + 8;
@@ -502,12 +479,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
dim->set_field(tagId);
dim->add_child()->set_field(1);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, _, _))
@@ -577,12 +550,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
@@ -657,12 +626,8 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
@@ -729,12 +694,8 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
@@ -807,12 +768,8 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _))
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 98892507e78d..5524ebc86b36 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -46,7 +46,6 @@ namespace {
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
-const int64_t atomMatcherId = 678;
const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10000000000;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
@@ -99,12 +98,8 @@ class ValueMetricProducerTestHelper {
public:
static sp<ValueMetricProducer> createValueProducerNoConditions(
sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
.WillOnce(Return());
@@ -122,12 +117,8 @@ public:
static sp<ValueMetricProducer> createValueProducerWithCondition(
sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
ConditionState conditionAfterFirstBucketPrepared) {
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
.WillOnce(Return());
@@ -147,12 +138,8 @@ public:
sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
vector<int32_t> slicedStateAtoms,
unordered_map<int, unordered_map<int, int64_t>> stateGroupMap) {
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
.WillOnce(Return());
@@ -172,12 +159,8 @@ public:
vector<int32_t> slicedStateAtoms,
unordered_map<int, unordered_map<int, int64_t>> stateGroupMap,
ConditionState conditionAfterFirstBucketPrepared) {
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
.WillOnce(Return());
@@ -237,12 +220,8 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
int64_t startTimeBase = 11;
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -267,12 +246,8 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
TEST(ValueMetricProducerTest, TestFirstBucket) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -421,15 +396,11 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) {
TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- auto keyValue = atomMatcher.add_field_value_matcher();
- keyValue->set_field(1);
- keyValue->set_eq_int(3);
+ FieldValueMatcher fvm;
+ fvm.set_field(1);
+ fvm.set_eq_int(3);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex, {fvm});
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -698,12 +669,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -759,12 +726,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) {
TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150;
@@ -820,12 +783,8 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_split_bucket_for_app_upgrade(false);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -900,12 +859,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse
TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -944,12 +899,8 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1015,12 +966,8 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1360,12 +1307,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::MIN);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1404,12 +1347,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::MAX);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1447,12 +1386,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::AVG);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1495,12 +1430,8 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::SUM);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1539,12 +1470,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
metric.set_aggregation_type(ValueMetric::MIN);
metric.set_use_diff(true);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -1611,12 +1538,8 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
metric.set_aggregation_type(ValueMetric::MIN);
metric.set_use_diff(true);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -2140,12 +2063,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -2963,12 +2882,8 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -3001,12 +2916,8 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
@@ -3045,12 +2956,8 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ createEventMatcherWizard(tagId, logEventMatcherIndex);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
new file mode 100644
index 000000000000..6b50fe5387d7
--- /dev/null
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -0,0 +1,382 @@
+// Copyright (C) 2020 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 "src/metrics/parsing_utils/config_update_utils.h"
+
+#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+#include <stdio.h>
+
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/metrics/parsing_utils/metrics_manager_util.h"
+#include "tests/statsd_test_util.h"
+
+using namespace testing;
+using android::sp;
+using android::os::statsd::Predicate;
+using std::map;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+namespace {
+
+ConfigKey key(123, 456);
+const int64_t timeBaseNs = 1000;
+sp<UidMap> uidMap = new UidMap();
+sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+sp<AlarmMonitor> anomalyAlarmMonitor;
+sp<AlarmMonitor> periodicAlarmMonitor;
+set<int> allTagIds;
+vector<sp<LogMatchingTracker>> oldAtomMatchers;
+unordered_map<int64_t, int> oldLogTrackerMap;
+vector<sp<ConditionTracker>> oldConditionTrackers;
+vector<sp<MetricProducer>> oldMetricProducers;
+std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
+std::vector<sp<AlarmTracker>> oldAlarmTrackers;
+unordered_map<int, std::vector<int>> conditionToMetricMap;
+unordered_map<int, std::vector<int>> trackerToMetricMap;
+unordered_map<int, std::vector<int>> trackerToConditionMap;
+unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+unordered_map<int64_t, int> alertTrackerMap;
+vector<int> metricsWithActivation;
+std::set<int64_t> noReportMetricIds;
+
+class ConfigUpdateTest : public ::testing::Test {
+public:
+ ConfigUpdateTest() {
+ }
+
+ void SetUp() override {
+ allTagIds.clear();
+ oldAtomMatchers.clear();
+ oldLogTrackerMap.clear();
+ oldConditionTrackers.clear();
+ oldMetricProducers.clear();
+ oldAnomalyTrackers.clear();
+ oldAlarmTrackers.clear();
+ conditionToMetricMap.clear();
+ trackerToMetricMap.clear();
+ trackerToConditionMap.clear();
+ activationAtomTrackerToMetricMap.clear();
+ deactivationAtomTrackerToMetricMap.clear();
+ alertTrackerMap.clear();
+ metricsWithActivation.clear();
+ noReportMetricIds.clear();
+ }
+};
+
+bool initConfig(const StatsdConfig& config) {
+ return initStatsdConfig(key, config, uidMap, pullerManager, anomalyAlarmMonitor,
+ periodicAlarmMonitor, timeBaseNs, timeBaseNs, allTagIds,
+ oldAtomMatchers, oldLogTrackerMap, oldConditionTrackers,
+ oldMetricProducers, oldAnomalyTrackers, oldAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ alertTrackerMap, metricsWithActivation, noReportMetricIds);
+}
+
+} // anonymous namespace
+
+TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) {
+ StatsdConfig config;
+ AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
+ int64_t matcherId = matcher.id();
+ *config.add_atom_matcher() = matcher;
+
+ // Create an initial config.
+ EXPECT_TRUE(initConfig(config));
+
+ vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newLogTrackerMap;
+ newLogTrackerMap[matcherId] = 0;
+ EXPECT_TRUE(determineMatcherUpdateStatus(config, 0, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) {
+ StatsdConfig config;
+ AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
+ *config.add_atom_matcher() = matcher;
+
+ EXPECT_TRUE(initConfig(config));
+
+ StatsdConfig newConfig;
+ // Same id, different atom, so should be replaced.
+ AtomMatcher newMatcher = CreateSimpleAtomMatcher("TEST", /*atom=*/11);
+ int64_t matcherId = newMatcher.id();
+ EXPECT_EQ(matcherId, matcher.id());
+ *newConfig.add_atom_matcher() = newMatcher;
+
+ vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(1, false);
+ unordered_map<int64_t, int> newLogTrackerMap;
+ newLogTrackerMap[matcherId] = 0;
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) {
+ StatsdConfig config;
+ AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
+ int64_t matcher1Id = matcher1.id();
+ *config.add_atom_matcher() = matcher1;
+
+ AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
+ *config.add_atom_matcher() = matcher2;
+ int64_t matcher2Id = matcher2.id();
+
+ AtomMatcher matcher3;
+ matcher3.set_id(StringToId("TEST3"));
+ AtomMatcher_Combination* combination = matcher3.mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(matcher1Id);
+ combination->add_matcher(matcher2Id);
+ int64_t matcher3Id = matcher3.id();
+ *config.add_atom_matcher() = matcher3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newLogTrackerMap;
+ // Same matchers, different order, all should be preserved.
+ *newConfig.add_atom_matcher() = matcher2;
+ newLogTrackerMap[matcher2Id] = 0;
+ *newConfig.add_atom_matcher() = matcher3;
+ newLogTrackerMap[matcher3Id] = 1;
+ *newConfig.add_atom_matcher() = matcher1;
+ newLogTrackerMap[matcher1Id] = 2;
+
+ vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. It should recurse the two child matchers and preserve all 3.
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
+ EXPECT_EQ(matchersToUpdate[1], UPDATE_PRESERVE);
+ EXPECT_EQ(matchersToUpdate[2], UPDATE_PRESERVE);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationMatcherReplace) {
+ StatsdConfig config;
+ AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
+ int64_t matcher1Id = matcher1.id();
+ *config.add_atom_matcher() = matcher1;
+
+ AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
+ *config.add_atom_matcher() = matcher2;
+ int64_t matcher2Id = matcher2.id();
+
+ AtomMatcher matcher3;
+ matcher3.set_id(StringToId("TEST3"));
+ AtomMatcher_Combination* combination = matcher3.mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(matcher1Id);
+ combination->add_matcher(matcher2Id);
+ int64_t matcher3Id = matcher3.id();
+ *config.add_atom_matcher() = matcher3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Change the logical operation of the combination matcher, causing a replacement.
+ matcher3.mutable_combination()->set_operation(LogicalOperation::AND);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newLogTrackerMap;
+ *newConfig.add_atom_matcher() = matcher2;
+ newLogTrackerMap[matcher2Id] = 0;
+ *newConfig.add_atom_matcher() = matcher3;
+ newLogTrackerMap[matcher3Id] = 1;
+ *newConfig.add_atom_matcher() = matcher1;
+ newLogTrackerMap[matcher1Id] = 2;
+
+ vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination. The simple matchers should not be evaluated.
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker));
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_UNKNOWN);
+ EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
+ EXPECT_EQ(matchersToUpdate[2], UPDATE_UNKNOWN);
+}
+
+TEST_F(ConfigUpdateTest, TestCombinationMatcherDepsChange) {
+ StatsdConfig config;
+ AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
+ int64_t matcher1Id = matcher1.id();
+ *config.add_atom_matcher() = matcher1;
+
+ AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
+ *config.add_atom_matcher() = matcher2;
+ int64_t matcher2Id = matcher2.id();
+
+ AtomMatcher matcher3;
+ matcher3.set_id(StringToId("TEST3"));
+ AtomMatcher_Combination* combination = matcher3.mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(matcher1Id);
+ combination->add_matcher(matcher2Id);
+ int64_t matcher3Id = matcher3.id();
+ *config.add_atom_matcher() = matcher3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Change a dependency of matcher 3.
+ matcher2.mutable_simple_atom_matcher()->set_atom_id(12);
+
+ StatsdConfig newConfig;
+ unordered_map<int64_t, int> newLogTrackerMap;
+ *newConfig.add_atom_matcher() = matcher2;
+ newLogTrackerMap[matcher2Id] = 0;
+ *newConfig.add_atom_matcher() = matcher3;
+ newLogTrackerMap[matcher3Id] = 1;
+ *newConfig.add_atom_matcher() = matcher1;
+ newLogTrackerMap[matcher1Id] = 2;
+
+ vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
+ vector<bool> cycleTracker(3, false);
+ // Only update the combination.
+ EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldLogTrackerMap, oldAtomMatchers,
+ newLogTrackerMap, matchersToUpdate, cycleTracker));
+ // Matcher 2 and matcher3 must be reevaluated. Matcher 1 might, but does not need to be.
+ EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
+ EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
+}
+
+TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
+ StatsdConfig config;
+ // Will be preserved.
+ AtomMatcher simple1 = CreateSimpleAtomMatcher("SIMPLE1", /*atom=*/10);
+ int64_t simple1Id = simple1.id();
+ *config.add_atom_matcher() = simple1;
+
+ // Will be replaced.
+ AtomMatcher simple2 = CreateSimpleAtomMatcher("SIMPLE2", /*atom=*/11);
+ *config.add_atom_matcher() = simple2;
+ int64_t simple2Id = simple2.id();
+
+ // Will be removed.
+ AtomMatcher simple3 = CreateSimpleAtomMatcher("SIMPLE3", /*atom=*/12);
+ *config.add_atom_matcher() = simple3;
+ int64_t simple3Id = simple3.id();
+
+ // Will be preserved.
+ AtomMatcher combination1;
+ combination1.set_id(StringToId("combination1"));
+ AtomMatcher_Combination* combination = combination1.mutable_combination();
+ combination->set_operation(LogicalOperation::NOT);
+ combination->add_matcher(simple1Id);
+ int64_t combination1Id = combination1.id();
+ *config.add_atom_matcher() = combination1;
+
+ // Will be replaced since it depends on simple2.
+ AtomMatcher combination2;
+ combination2.set_id(StringToId("combination2"));
+ combination = combination2.mutable_combination();
+ combination->set_operation(LogicalOperation::AND);
+ combination->add_matcher(simple1Id);
+ combination->add_matcher(simple2Id);
+ int64_t combination2Id = combination2.id();
+ *config.add_atom_matcher() = combination2;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Change simple2, causing simple2 and combination2 to be replaced.
+ simple2.mutable_simple_atom_matcher()->set_atom_id(111);
+
+ // 2 new matchers: simple4 and combination3:
+ AtomMatcher simple4 = CreateSimpleAtomMatcher("SIMPLE4", /*atom=*/13);
+ int64_t simple4Id = simple4.id();
+
+ AtomMatcher combination3;
+ combination3.set_id(StringToId("combination3"));
+ combination = combination3.mutable_combination();
+ combination->set_operation(LogicalOperation::AND);
+ combination->add_matcher(simple4Id);
+ combination->add_matcher(simple2Id);
+ int64_t combination3Id = combination3.id();
+
+ StatsdConfig newConfig;
+ *newConfig.add_atom_matcher() = combination3;
+ *newConfig.add_atom_matcher() = simple2;
+ *newConfig.add_atom_matcher() = combination2;
+ *newConfig.add_atom_matcher() = simple1;
+ *newConfig.add_atom_matcher() = simple4;
+ *newConfig.add_atom_matcher() = combination1;
+
+ set<int> newTagIds;
+ unordered_map<int64_t, int> newLogTrackerMap;
+ vector<sp<LogMatchingTracker>> newAtomMatchers;
+ EXPECT_TRUE(updateLogTrackers(newConfig, uidMap, oldLogTrackerMap, oldAtomMatchers, newTagIds,
+ newLogTrackerMap, newAtomMatchers));
+
+ ASSERT_EQ(newTagIds.size(), 3);
+ EXPECT_EQ(newTagIds.count(10), 1);
+ EXPECT_EQ(newTagIds.count(111), 1);
+ EXPECT_EQ(newTagIds.count(13), 1);
+
+ ASSERT_EQ(newLogTrackerMap.size(), 6);
+ EXPECT_EQ(newLogTrackerMap.at(combination3Id), 0);
+ EXPECT_EQ(newLogTrackerMap.at(simple2Id), 1);
+ EXPECT_EQ(newLogTrackerMap.at(combination2Id), 2);
+ EXPECT_EQ(newLogTrackerMap.at(simple1Id), 3);
+ EXPECT_EQ(newLogTrackerMap.at(simple4Id), 4);
+ EXPECT_EQ(newLogTrackerMap.at(combination1Id), 5);
+
+ ASSERT_EQ(newAtomMatchers.size(), 6);
+ // Make sure all atom matchers are initialized:
+ for (const sp<LogMatchingTracker>& tracker : newAtomMatchers) {
+ EXPECT_TRUE(tracker->mInitialized);
+ }
+ // Make sure preserved atom matchers are the same.
+ EXPECT_EQ(oldAtomMatchers[oldLogTrackerMap.at(simple1Id)],
+ newAtomMatchers[newLogTrackerMap.at(simple1Id)]);
+ EXPECT_EQ(oldAtomMatchers[oldLogTrackerMap.at(combination1Id)],
+ newAtomMatchers[newLogTrackerMap.at(combination1Id)]);
+ // Make sure replaced matchers are different.
+ EXPECT_NE(oldAtomMatchers[oldLogTrackerMap.at(simple2Id)],
+ newAtomMatchers[newLogTrackerMap.at(simple2Id)]);
+ EXPECT_NE(oldAtomMatchers[oldLogTrackerMap.at(combination2Id)],
+ newAtomMatchers[newLogTrackerMap.at(combination2Id)]);
+
+ // Validation, make sure the matchers have the proper ids. Could do more checks here.
+ EXPECT_EQ(newAtomMatchers[0]->getId(), combination3Id);
+ EXPECT_EQ(newAtomMatchers[1]->getId(), simple2Id);
+ EXPECT_EQ(newAtomMatchers[2]->getId(), combination2Id);
+ EXPECT_EQ(newAtomMatchers[3]->getId(), simple1Id);
+ EXPECT_EQ(newAtomMatchers[4]->getId(), simple4Id);
+ EXPECT_EQ(newAtomMatchers[5]->getId(), combination1Id);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
new file mode 100644
index 000000000000..4e97eaf6f149
--- /dev/null
+++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -0,0 +1,708 @@
+// Copyright (C) 2020 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 "src/metrics/parsing_utils/metrics_manager_util.h"
+
+#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+#include <stdio.h>
+
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "src/condition/ConditionTracker.h"
+#include "src/matchers/LogMatchingTracker.h"
+#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/GaugeMetricProducer.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/metrics/ValueMetricProducer.h"
+#include "src/state/StateManager.h"
+#include "tests/metrics/metrics_test_helper.h"
+#include "tests/statsd_test_util.h"
+
+using namespace testing;
+using android::sp;
+using android::os::statsd::Predicate;
+using std::map;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+namespace {
+const ConfigKey kConfigKey(0, 12345);
+const long kAlertId = 3;
+
+const long timeBaseSec = 1000;
+
+StatsdConfig buildGoodConfig() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
+
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
+
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
+ combination->add_matcher(StringToId("SCREEN_IS_OFF"));
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_IS_ON"));
+ metric->set_bucket(ONE_MINUTE);
+ metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
+ metric->mutable_dimensions_in_what()->add_child()->set_field(1);
+
+ config.add_no_report_metric(3);
+
+ auto alert = config.add_alert();
+ alert->set_id(kAlertId);
+ alert->set_metric_id(3);
+ alert->set_num_buckets(10);
+ alert->set_refractory_period_secs(100);
+ alert->set_trigger_if_sum_gt(100);
+ return config;
+}
+
+StatsdConfig buildCircleMatchers() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
+
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
+ // Circle dependency
+ combination->add_matcher(StringToId("SCREEN_ON_OR_OFF"));
+
+ return config;
+}
+
+StatsdConfig buildAlertWithUnknownMetric() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_IS_ON"));
+ metric->set_bucket(ONE_MINUTE);
+ metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
+ metric->mutable_dimensions_in_what()->add_child()->set_field(1);
+
+ auto alert = config.add_alert();
+ alert->set_id(3);
+ alert->set_metric_id(2);
+ alert->set_num_buckets(10);
+ alert->set_refractory_period_secs(100);
+ alert->set_trigger_if_sum_gt(100);
+ return config;
+}
+
+StatsdConfig buildMissingMatchers() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
+
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(StringToId("SCREEN_IS_ON"));
+ // undefined matcher
+ combination->add_matcher(StringToId("ABC"));
+
+ return config;
+}
+
+StatsdConfig buildMissingPredicate() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ CountMetric* metric = config.add_count_metric();
+ metric->set_id(3);
+ metric->set_what(StringToId("SCREEN_EVENT"));
+ metric->set_bucket(ONE_MINUTE);
+ metric->set_condition(StringToId("SOME_CONDITION"));
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_EVENT"));
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2);
+
+ return config;
+}
+
+StatsdConfig buildDimensionMetricsWithMultiTags() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("BATTERY_VERY_LOW"));
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW"));
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(3);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("BATTERY_LOW"));
+
+ AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(StringToId("BATTERY_VERY_LOW"));
+ combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW"));
+
+ // Count process state changes, slice by uid, while SCREEN_IS_OFF
+ CountMetric* metric = config.add_count_metric();
+ metric->set_id(3);
+ metric->set_what(StringToId("BATTERY_LOW"));
+ metric->set_bucket(ONE_MINUTE);
+ // This case is interesting. We want to dimension across two atoms.
+ metric->mutable_dimensions_in_what()->add_child()->set_field(1);
+
+ auto alert = config.add_alert();
+ alert->set_id(kAlertId);
+ alert->set_metric_id(3);
+ alert->set_num_buckets(10);
+ alert->set_refractory_period_secs(100);
+ alert->set_trigger_if_sum_gt(100);
+ return config;
+}
+
+StatsdConfig buildCirclePredicates() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ AtomMatcher* eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
+
+ SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_atom_matcher();
+ eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
+
+ simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+ auto condition = config.add_predicate();
+ condition->set_id(StringToId("SCREEN_IS_ON"));
+ SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
+ simplePredicate->set_start(StringToId("SCREEN_IS_ON"));
+ simplePredicate->set_stop(StringToId("SCREEN_IS_OFF"));
+
+ condition = config.add_predicate();
+ condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF"));
+
+ Predicate_Combination* combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_predicate(StringToId("SCREEN_IS_ON"));
+ combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF"));
+
+ return config;
+}
+
+StatsdConfig buildConfigWithDifferentPredicates() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ auto pulledAtomMatcher =
+ CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE);
+ *config.add_atom_matcher() = pulledAtomMatcher;
+ auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnAtomMatcher;
+ auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffAtomMatcher;
+ auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher();
+ *config.add_atom_matcher() = batteryNoneAtomMatcher;
+ auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher();
+ *config.add_atom_matcher() = batteryUsbAtomMatcher;
+
+ // Simple condition with InitialValue set to default (unknown).
+ auto screenOnUnknownPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = screenOnUnknownPredicate;
+
+ // Simple condition with InitialValue set to false.
+ auto screenOnFalsePredicate = config.add_predicate();
+ screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse"));
+ SimplePredicate* simpleScreenOnFalsePredicate =
+ screenOnFalsePredicate->mutable_simple_predicate();
+ simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id());
+ simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id());
+ simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+
+ // Simple condition with InitialValue set to false.
+ auto onBatteryFalsePredicate = config.add_predicate();
+ onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse"));
+ SimplePredicate* simpleOnBatteryFalsePredicate =
+ onBatteryFalsePredicate->mutable_simple_predicate();
+ simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id());
+ simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id());
+ simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+
+ // Combination condition with both simple condition InitialValues set to false.
+ auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate();
+ screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse"));
+ screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation(
+ LogicalOperation::AND);
+ addPredicateToPredicateCombination(*screenOnFalsePredicate,
+ screenOnFalseOnBatteryFalsePredicate);
+ addPredicateToPredicateCombination(*onBatteryFalsePredicate,
+ screenOnFalseOnBatteryFalsePredicate);
+
+ // Combination condition with one simple condition InitialValue set to unknown and one set to
+ // false.
+ auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate();
+ screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse"));
+ screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation(
+ LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenOnUnknownPredicate,
+ screenOnUnknownOnBatteryFalsePredicate);
+ addPredicateToPredicateCombination(*onBatteryFalsePredicate,
+ screenOnUnknownOnBatteryFalsePredicate);
+
+ // Simple condition metric with initial value false.
+ ValueMetric* metric1 = config.add_value_metric();
+ metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse"));
+ metric1->set_what(pulledAtomMatcher.id());
+ *metric1->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric1->set_bucket(FIVE_MINUTES);
+ metric1->set_condition(screenOnFalsePredicate->id());
+
+ // Simple condition metric with initial value unknown.
+ ValueMetric* metric2 = config.add_value_metric();
+ metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown"));
+ metric2->set_what(pulledAtomMatcher.id());
+ *metric2->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric2->set_bucket(FIVE_MINUTES);
+ metric2->set_condition(screenOnUnknownPredicate.id());
+
+ // Combination condition metric with initial values false and false.
+ ValueMetric* metric3 = config.add_value_metric();
+ metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse"));
+ metric3->set_what(pulledAtomMatcher.id());
+ *metric3->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric3->set_bucket(FIVE_MINUTES);
+ metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id());
+
+ // Combination condition metric with initial values unknown and false.
+ ValueMetric* metric4 = config.add_value_metric();
+ metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse"));
+ metric4->set_what(pulledAtomMatcher.id());
+ *metric4->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric4->set_bucket(FIVE_MINUTES);
+ metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id());
+
+ return config;
+}
+} // anonymous namespace
+
+TEST(MetricsManagerTest, TestInitialConditions) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildConfigWithDifferentPredicates();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_TRUE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+ ASSERT_EQ(4u, allMetricProducers.size());
+ ASSERT_EQ(5u, allConditionTrackers.size());
+
+ ConditionKey queryKey;
+ vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
+
+ allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
+ allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[1]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[2]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[3]);
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]);
+
+ EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition);
+ EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition);
+ EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition);
+ EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition);
+}
+
+TEST(MetricsManagerTest, TestGoodConfig) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildGoodConfig();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_TRUE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+ ASSERT_EQ(1u, allMetricProducers.size());
+ ASSERT_EQ(1u, allAnomalyTrackers.size());
+ ASSERT_EQ(1u, noReportMetricIds.size());
+ ASSERT_EQ(1u, alertTrackerMap.size());
+ EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
+ EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
+}
+
+TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildDimensionMetricsWithMultiTags();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildCircleMatchers();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, TestMissingMatchers) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildMissingMatchers();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, TestMissingPredicate) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildMissingPredicate();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, TestCirclePredicateDependency) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildCirclePredicates();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
+ sp<UidMap> uidMap = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildAlertWithUnknownMetric();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ unordered_map<int64_t, int> logTrackerMap;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_FALSE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, logTrackerMap,
+ allConditionTrackers, allMetricProducers, allAnomalyTrackers, allAlarmTrackers,
+ conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap, alertTrackerMap,
+ metricsWithActivation, noReportMetricIds));
+}
+
+TEST(MetricsManagerTest, TestCreateLogTrackerInvalidMatcher) {
+ sp<UidMap> uidMap = new UidMap();
+ AtomMatcher matcher;
+ matcher.set_id(21);
+ EXPECT_EQ(createLogTracker(matcher, 0, uidMap), nullptr);
+}
+
+TEST(MetricsManagerTest, TestCreateLogTrackerSimple) {
+ int index = 1;
+ int64_t id = 123;
+ sp<UidMap> uidMap = new UidMap();
+ AtomMatcher matcher;
+ matcher.set_id(id);
+ SimpleAtomMatcher* simpleAtomMatcher = matcher.mutable_simple_atom_matcher();
+ simpleAtomMatcher->set_atom_id(util::SCREEN_STATE_CHANGED);
+ simpleAtomMatcher->add_field_value_matcher()->set_field(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ sp<LogMatchingTracker> tracker = createLogTracker(matcher, index, uidMap);
+ EXPECT_NE(tracker, nullptr);
+
+ EXPECT_TRUE(tracker->mInitialized);
+ EXPECT_EQ(tracker->getId(), id);
+ EXPECT_EQ(tracker->mIndex, index);
+ const set<int>& atomIds = tracker->getAtomIds();
+ ASSERT_EQ(atomIds.size(), 1);
+ EXPECT_EQ(atomIds.count(util::SCREEN_STATE_CHANGED), 1);
+}
+
+TEST(MetricsManagerTest, TestCreateLogTrackerCombination) {
+ int index = 1;
+ int64_t id = 123;
+ sp<UidMap> uidMap = new UidMap();
+ AtomMatcher matcher;
+ matcher.set_id(id);
+ AtomMatcher_Combination* combination = matcher.mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher(123);
+ combination->add_matcher(223);
+
+ sp<LogMatchingTracker> tracker = createLogTracker(matcher, index, uidMap);
+ EXPECT_NE(tracker, nullptr);
+
+ // Combination matchers need to be initialized first.
+ EXPECT_FALSE(tracker->mInitialized);
+ EXPECT_EQ(tracker->getId(), id);
+ EXPECT_EQ(tracker->mIndex, index);
+ const set<int>& atomIds = tracker->getAtomIds();
+ ASSERT_EQ(atomIds.size(), 0);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index cee83725d075..0be983f2a9b0 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -15,6 +15,8 @@
#include "statsd_test_util.h"
#include <aidl/android/util/StatsEventParcel.h>
+
+#include "matchers/SimpleLogMatchingTracker.h"
#include "stats_event.h"
using aidl::android::util::StatsEventParcel;
@@ -996,6 +998,20 @@ int64_t StringToId(const string& str) {
return static_cast<int64_t>(std::hash<std::string>()(str));
}
+sp<EventMatcherWizard> createEventMatcherWizard(
+ int tagId, int matcherIndex, const vector<FieldValueMatcher>& fieldValueMatchers) {
+ sp<UidMap> uidMap = new UidMap();
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ for (const FieldValueMatcher& fvm : fieldValueMatchers) {
+ *atomMatcher.add_field_value_matcher() = fvm;
+ }
+ uint64_t matcherHash = 0x12345678;
+ int64_t matcherId = 678;
+ return new EventMatcherWizard({new SimpleLogMatchingTracker(matcherId, matcherIndex,
+ matcherHash, atomMatcher, uidMap)});
+}
+
void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId,
const int uid, const string& tag) {
EXPECT_EQ(value.field(), atomId);
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 3dcf4ecce054..1220019e2353 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -25,6 +25,7 @@
#include "src/StatsLogProcessor.h"
#include "src/hash.h"
#include "src/logd/LogEvent.h"
+#include "src/matchers/EventMatcherWizard.h"
#include "src/packages/UidMap.h"
#include "src/stats_log_util.h"
#include "stats_event.h"
@@ -335,6 +336,9 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
int64_t StringToId(const string& str);
+sp<EventMatcherWizard> createEventMatcherWizard(
+ int tagId, int matcherIndex, const std::vector<FieldValueMatcher>& fieldValueMatchers = {});
+
void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId,
const int uid, const string& tag);
void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 522b8cc5a46f..5c4951e23ea2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3827,6 +3827,12 @@ public class Activity extends ContextThemeWrapper
} catch (RemoteException e) {
finishAfterTransition();
}
+
+ // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
+ // be restored now.
+ if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
+ restoreAutofillSaveUi();
+ }
}
/**
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 68e65612971c..6f3e89229e4c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1492,6 +1492,7 @@ public class Notification implements Parcelable
private boolean mAllowGeneratedReplies = true;
private final @SemanticAction int mSemanticAction;
private final boolean mIsContextual;
+ private boolean mAuthenticationRequired;
/**
* Small icon representing the action.
@@ -1528,6 +1529,7 @@ public class Notification implements Parcelable
mAllowGeneratedReplies = in.readInt() == 1;
mSemanticAction = in.readInt();
mIsContextual = in.readInt() == 1;
+ mAuthenticationRequired = in.readInt() == 1;
}
/**
@@ -1536,13 +1538,14 @@ public class Notification implements Parcelable
@Deprecated
public Action(int icon, CharSequence title, PendingIntent intent) {
this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true,
- SEMANTIC_ACTION_NONE, false /* isContextual */);
+ SEMANTIC_ACTION_NONE, false /* isContextual */, false /* requireAuth */);
}
/** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction, boolean isContextual) {
+ @SemanticAction int semanticAction, boolean isContextual,
+ boolean requireAuth) {
this.mIcon = icon;
if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
this.icon = icon.getResId();
@@ -1554,6 +1557,7 @@ public class Notification implements Parcelable
this.mAllowGeneratedReplies = allowGeneratedReplies;
this.mSemanticAction = semanticAction;
this.mIsContextual = isContextual;
+ this.mAuthenticationRequired = requireAuth;
}
/**
@@ -1624,6 +1628,17 @@ public class Notification implements Parcelable
}
/**
+ * Returns whether the OS should only send this action's {@link PendingIntent} on an
+ * unlocked device.
+ *
+ * If the device is locked when the action is invoked, the OS should show the keyguard and
+ * require successful authentication before invoking the intent.
+ */
+ public boolean isAuthenticationRequired() {
+ return mAuthenticationRequired;
+ }
+
+ /**
* Builder class for {@link Action} objects.
*/
public static final class Builder {
@@ -1635,6 +1650,7 @@ public class Notification implements Parcelable
@Nullable private ArrayList<RemoteInput> mRemoteInputs;
private @SemanticAction int mSemanticAction;
private boolean mIsContextual;
+ private boolean mAuthenticationRequired;
/**
* Construct a new builder for {@link Action} object.
@@ -1654,7 +1670,7 @@ public class Notification implements Parcelable
* @param intent the {@link PendingIntent} to fire when users trigger this action
*/
public Builder(Icon icon, CharSequence title, PendingIntent intent) {
- this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE);
+ this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, false);
}
/**
@@ -1665,23 +1681,25 @@ public class Notification implements Parcelable
public Builder(Action action) {
this(action.getIcon(), action.title, action.actionIntent,
new Bundle(action.mExtras), action.getRemoteInputs(),
- action.getAllowGeneratedReplies(), action.getSemanticAction());
+ action.getAllowGeneratedReplies(), action.getSemanticAction(),
+ action.isAuthenticationRequired());
}
private Builder(@Nullable Icon icon, @Nullable CharSequence title,
@Nullable PendingIntent intent, @NonNull Bundle extras,
@Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction) {
+ @SemanticAction int semanticAction, boolean authRequired) {
mIcon = icon;
mTitle = title;
mIntent = intent;
mExtras = extras;
if (remoteInputs != null) {
- mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
+ mRemoteInputs = new ArrayList<>(remoteInputs.length);
Collections.addAll(mRemoteInputs, remoteInputs);
}
mAllowGeneratedReplies = allowGeneratedReplies;
mSemanticAction = semanticAction;
+ mAuthenticationRequired = authRequired;
}
/**
@@ -1776,6 +1794,21 @@ public class Notification implements Parcelable
}
/**
+ * Sets whether the OS should only send this action's {@link PendingIntent} on an
+ * unlocked device.
+ *
+ * If this is true and the device is locked when the action is invoked, the OS will
+ * show the keyguard and require successful authentication before invoking the intent.
+ * If this is false and the device is locked, the OS will decide whether authentication
+ * should be required.
+ */
+ @NonNull
+ public Builder setAuthenticationRequired(boolean authenticationRequired) {
+ mAuthenticationRequired = authenticationRequired;
+ return this;
+ }
+
+ /**
* Throws an NPE if we are building a contextual action missing one of the fields
* necessary to display the action.
*/
@@ -1827,7 +1860,8 @@ public class Notification implements Parcelable
RemoteInput[] textInputsArr = textInputs.isEmpty()
? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
- mAllowGeneratedReplies, mSemanticAction, mIsContextual);
+ mAllowGeneratedReplies, mSemanticAction, mIsContextual,
+ mAuthenticationRequired);
}
}
@@ -1841,7 +1875,8 @@ public class Notification implements Parcelable
getRemoteInputs(),
getAllowGeneratedReplies(),
getSemanticAction(),
- isContextual());
+ isContextual(),
+ isAuthenticationRequired());
}
@Override
@@ -1870,6 +1905,7 @@ public class Notification implements Parcelable
out.writeInt(mAllowGeneratedReplies ? 1 : 0);
out.writeInt(mSemanticAction);
out.writeInt(mIsContextual ? 1 : 0);
+ out.writeInt(mAuthenticationRequired ? 1 : 0);
}
public static final @android.annotation.NonNull Parcelable.Creator<Action> CREATOR =
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 16ddcd1d0ea3..056cfc7c28f1 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -402,7 +402,7 @@ public abstract class BackupAgent extends ContextWrapper {
*/
public void onFullBackup(FullBackupDataOutput data) throws IOException {
FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this);
- if (!backupScheme.isFullBackupContentEnabled()) {
+ if (!isDeviceToDeviceMigration() && !backupScheme.isFullBackupContentEnabled()) {
return;
}
@@ -430,24 +430,18 @@ public abstract class BackupAgent extends ContextWrapper {
final Context ceContext = createCredentialProtectedStorageContext();
final String rootDir = ceContext.getDataDir().getCanonicalPath();
final String filesDir = ceContext.getFilesDir().getCanonicalPath();
- final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
final String databaseDir = ceContext.getDatabasePath("foo").getParentFile()
.getCanonicalPath();
final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile()
.getCanonicalPath();
- final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
- final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
final Context deContext = createDeviceProtectedStorageContext();
final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
- final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile()
.getCanonicalPath();
final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo")
.getParentFile().getCanonicalPath();
- final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
- final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
final String libDir = (appInfo.nativeLibraryDir != null)
? new File(appInfo.nativeLibraryDir).getCanonicalPath()
@@ -460,33 +454,36 @@ public abstract class BackupAgent extends ContextWrapper {
// Add the directories we always exclude.
traversalExcludeSet.add(filesDir);
- traversalExcludeSet.add(noBackupDir);
traversalExcludeSet.add(databaseDir);
traversalExcludeSet.add(sharedPrefsDir);
- traversalExcludeSet.add(cacheDir);
- traversalExcludeSet.add(codeCacheDir);
traversalExcludeSet.add(deviceFilesDir);
- traversalExcludeSet.add(deviceNoBackupDir);
traversalExcludeSet.add(deviceDatabaseDir);
traversalExcludeSet.add(deviceSharedPrefsDir);
- traversalExcludeSet.add(deviceCacheDir);
- traversalExcludeSet.add(deviceCodeCacheDir);
if (libDir != null) {
traversalExcludeSet.add(libDir);
}
+ Set<String> extraExcludedDirs = getExtraExcludeDirsIfAny(ceContext);
+ Set<String> extraExcludedDeviceDirs = getExtraExcludeDirsIfAny(deContext);
+ traversalExcludeSet.addAll(extraExcludedDirs);
+ traversalExcludeSet.addAll(extraExcludedDeviceDirs);
+
// Root dir first.
applyXmlFiltersAndDoFullBackupForDomain(
packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(rootDir);
+ // Exclude the extra directories anyway, since we've already covered them if it was needed.
+ traversalExcludeSet.addAll(extraExcludedDirs);
applyXmlFiltersAndDoFullBackupForDomain(
packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(deviceRootDir);
+ // Exclude the extra directories anyway, since we've already covered them if it was needed.
+ traversalExcludeSet.addAll(extraExcludedDeviceDirs);
// Data dir next.
traversalExcludeSet.remove(filesDir);
@@ -545,11 +542,28 @@ public abstract class BackupAgent extends ContextWrapper {
}
}
+ private Set<String> getExtraExcludeDirsIfAny(Context context) throws IOException {
+ if (isDeviceToDeviceMigration()) {
+ return Collections.emptySet();
+ }
+
+ // If this is not a migration, also exclude no-backup and cache dirs.
+ Set<String> excludedDirs = new HashSet<>();
+ excludedDirs.add(context.getCacheDir().getCanonicalPath());
+ excludedDirs.add(context.getCodeCacheDir().getCanonicalPath());
+ excludedDirs.add(context.getNoBackupFilesDir().getCanonicalPath());
+ return Collections.unmodifiableSet(excludedDirs);
+ }
+
+ private boolean isDeviceToDeviceMigration() {
+ return mOperationType == OperationType.MIGRATION;
+ }
+
/** @hide */
@VisibleForTesting
public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme)
throws IOException, XmlPullParserException {
- if (mOperationType == OperationType.MIGRATION) {
+ if (isDeviceToDeviceMigration()) {
return IncludeExcludeRules.emptyRules();
}
@@ -892,6 +906,11 @@ public abstract class BackupAgent extends ContextWrapper {
}
private boolean isFileEligibleForRestore(File destination) throws IOException {
+ if (isDeviceToDeviceMigration()) {
+ // Everything is eligible for device-to-device migration.
+ return true;
+ }
+
FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this);
if (!bs.isFullBackupContentEnabled()) {
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
diff --git a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
index 236b0064763e..cc0af3f97e49 100644
--- a/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
+++ b/core/java/android/app/timezonedetector/TimeZoneCapabilities.java
@@ -91,11 +91,13 @@ public final class TimeZoneCapabilities implements Parcelable {
private final @UserIdInt int mUserId;
private final @CapabilityState int mConfigureAutoDetectionEnabled;
+ private final @CapabilityState int mConfigureGeoDetectionEnabled;
private final @CapabilityState int mSuggestManualTimeZone;
private TimeZoneCapabilities(@NonNull Builder builder) {
this.mUserId = builder.mUserId;
this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
+ this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
}
@@ -103,6 +105,7 @@ public final class TimeZoneCapabilities implements Parcelable {
private static TimeZoneCapabilities createFromParcel(Parcel in) {
return new TimeZoneCapabilities.Builder(in.readInt())
.setConfigureAutoDetectionEnabled(in.readInt())
+ .setConfigureGeoDetectionEnabled(in.readInt())
.setSuggestManualTimeZone(in.readInt())
.build();
}
@@ -111,6 +114,7 @@ public final class TimeZoneCapabilities implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mUserId);
dest.writeInt(mConfigureAutoDetectionEnabled);
+ dest.writeInt(mConfigureGeoDetectionEnabled);
dest.writeInt(mSuggestManualTimeZone);
}
@@ -120,8 +124,8 @@ public final class TimeZoneCapabilities implements Parcelable {
}
/**
- * Returns the user's capability state for controlling automatic time zone detection via
- * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
+ * Returns the user's capability state for controlling whether automatic time zone detection is
+ * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
* TimeZoneConfiguration#isAutoDetectionEnabled()}.
*/
@CapabilityState
@@ -130,6 +134,16 @@ public final class TimeZoneCapabilities implements Parcelable {
}
/**
+ * Returns the user's capability state for controlling whether geolocation can be used to detect
+ * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
+ * TimeZoneConfiguration#isGeoDetectionEnabled()}.
+ */
+ @CapabilityState
+ public int getConfigureGeoDetectionEnabled() {
+ return mConfigureGeoDetectionEnabled;
+ }
+
+ /**
* Returns the user's capability state for manually setting the time zone on a device via
* {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
*
@@ -157,12 +171,16 @@ public final class TimeZoneCapabilities implements Parcelable {
TimeZoneCapabilities that = (TimeZoneCapabilities) o;
return mUserId == that.mUserId
&& mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
+ && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
&& mSuggestManualTimeZone == that.mSuggestManualTimeZone;
}
@Override
public int hashCode() {
- return Objects.hash(mUserId, mConfigureAutoDetectionEnabled, mSuggestManualTimeZone);
+ return Objects.hash(mUserId,
+ mConfigureAutoDetectionEnabled,
+ mConfigureGeoDetectionEnabled,
+ mSuggestManualTimeZone);
}
@Override
@@ -170,6 +188,7 @@ public final class TimeZoneCapabilities implements Parcelable {
return "TimeZoneDetectorCapabilities{"
+ "mUserId=" + mUserId
+ ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
+ + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
+ ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
+ '}';
}
@@ -179,6 +198,7 @@ public final class TimeZoneCapabilities implements Parcelable {
private final @UserIdInt int mUserId;
private @CapabilityState int mConfigureAutoDetectionEnabled;
+ private @CapabilityState int mConfigureGeoDetectionEnabled;
private @CapabilityState int mSuggestManualTimeZone;
/**
@@ -194,6 +214,12 @@ public final class TimeZoneCapabilities implements Parcelable {
return this;
}
+ /** Sets the state for the geolocation time zone detection enabled config. */
+ public Builder setConfigureGeoDetectionEnabled(@CapabilityState int value) {
+ this.mConfigureGeoDetectionEnabled = value;
+ return this;
+ }
+
/** Sets the state for the suggestManualTimeZone action. */
public Builder setSuggestManualTimeZone(@CapabilityState int value) {
this.mSuggestManualTimeZone = value;
@@ -204,6 +230,7 @@ public final class TimeZoneCapabilities implements Parcelable {
@NonNull
public TimeZoneCapabilities build() {
verifyCapabilitySet(mConfigureAutoDetectionEnabled, "configureAutoDetectionEnabled");
+ verifyCapabilitySet(mConfigureGeoDetectionEnabled, "configureGeoDetectionEnabled");
verifyCapabilitySet(mSuggestManualTimeZone, "suggestManualTimeZone");
return new TimeZoneCapabilities(this);
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
index 047d3493d5dd..6f84ee22a985 100644
--- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
+++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java
@@ -67,6 +67,10 @@ public final class TimeZoneConfiguration implements Parcelable {
@Property
public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";
+ /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
+ @Property
+ public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled";
+
private final Bundle mBundle;
private TimeZoneConfiguration(Builder builder) {
@@ -86,7 +90,8 @@ public final class TimeZoneConfiguration implements Parcelable {
/** Returns {@code true} if all known properties are set. */
public boolean isComplete() {
- return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED);
+ return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
+ && hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
}
/** Returns true if the specified property is set. */
@@ -108,6 +113,28 @@ public final class TimeZoneConfiguration implements Parcelable {
return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED);
}
+ /**
+ * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This
+ * controls whether a device can use location to determine time zone. Only used when
+ * {@link #isAutoDetectionEnabled()} is true.
+ *
+ * @throws IllegalStateException if the field has not been set
+ */
+ public boolean isGeoDetectionEnabled() {
+ if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) {
+ throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set");
+ }
+ return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED);
+ }
+
+ /**
+ * Convenience method to merge this with another. The argument configuration properties have
+ * precedence.
+ */
+ public TimeZoneConfiguration with(TimeZoneConfiguration other) {
+ return new Builder(this).mergeProperties(other).build();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -174,6 +201,12 @@ public final class TimeZoneConfiguration implements Parcelable {
return this;
}
+ /** Sets the desired state of the geolocation time zone detection enabled property. */
+ public Builder setGeoDetectionEnabled(boolean enabled) {
+ this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled);
+ return this;
+ }
+
/** Returns the {@link TimeZoneConfiguration}. */
@NonNull
public TimeZoneConfiguration build() {
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 3522b1b8aff5..0e6a0637d801 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -199,7 +199,7 @@ public final class UsageEvents implements Parcelable {
public static final int NOTIFICATION_INTERRUPTION = 12;
/**
- * A Slice was pinned by the default launcher or the default assistant.
+ * A Slice was pinned by the default assistant.
* @hide
*/
@SystemApi
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
index e814ec649087..eb67191e5f54 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl
@@ -29,7 +29,7 @@ import android.view.accessibility.IWindowMagnificationConnectionCallback;
oneway interface IWindowMagnificationConnection {
/**
- * Enables window magnification on specifed display with specified center and scale.
+ * Enables window magnification on specified display with given center and scale and animation.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -41,7 +41,7 @@ oneway interface IWindowMagnificationConnection {
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
/**
- * Sets the scale of the window magnifier on specifed display.
+ * Sets the scale of the window magnifier on specified display.
*
* @param displayId The logical display id.
* @param scale magnification scale.
@@ -49,14 +49,14 @@ oneway interface IWindowMagnificationConnection {
void setScale(int displayId, float scale);
/**
- * Disables window magnification on specifed display.
+ * Disables window magnification on specified display with animation.
*
* @param displayId The logical display id.
*/
void disableWindowMagnification(int displayId);
/**
- * Moves the window magnifier on the specifed display.
+ * Moves the window magnifier on the specified display. It has no effect while animating.
*
* @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
* current screen pixels.
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index 9bf05135c4c5..a23fc4b57b45 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -291,7 +291,7 @@ public class ScreenshotHelper {
};
Message msg = Message.obtain(null, screenshotType, screenshotRequest);
- final ServiceConnection myConn = mScreenshotConnection;
+
Handler h = new Handler(handler.getLooper()) {
@Override
public void handleMessage(Message msg) {
@@ -304,8 +304,8 @@ public class ScreenshotHelper {
break;
case SCREENSHOT_MSG_PROCESS_COMPLETE:
synchronized (mScreenshotLock) {
- if (myConn != null && mScreenshotConnection == myConn) {
- mContext.unbindService(myConn);
+ if (mScreenshotConnection != null) {
+ mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mScreenshotService = null;
}
@@ -368,6 +368,7 @@ public class ScreenshotHelper {
}
} else {
Messenger messenger = new Messenger(mScreenshotService);
+
try {
messenger.send(msg);
} catch (RemoteException e) {
diff --git a/core/proto/android/app/tvsettings_enums.proto b/core/proto/android/app/tvsettings_enums.proto
index 31c5dd6b730a..4a3c59477f2f 100644
--- a/core/proto/android/app/tvsettings_enums.proto
+++ b/core/proto/android/app/tvsettings_enums.proto
@@ -168,7 +168,11 @@ enum ItemId {
// Google Assistant > Personal results (toggle)
ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT_PERSONAL_RESULTS = 0x12134000;
- // Reserving [0x12140000, 0x12190000] for possible future settings
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Apps only mode (toggle)
+ ACCOUNT_SLICE_REG_ACCOUNT_APPS_ONLY_MODE = 0x12140000;
+
+ // Reserving [0x12150000, 0x12190000] for possible future settings
// TvSettings > Account & Sign In (Slice) > [A regular account] > Remove
ACCOUNT_SLICE_REG_ACCOUNT_REMOVE = 0x121A0000;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fe290f3e97e8..edb972730f69 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1342,7 +1342,7 @@
android:priority="800" />
<!-- Allows an application to access data from sensors that the user uses to
- measure what is happening inside his/her body, such as heart rate.
+ measure what is happening inside their body, such as heart rate.
<p>Protection level: dangerous -->
<permission android:name="android.permission.BODY_SENSORS"
android:permissionGroup="android.permission-group.UNDEFINED"
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
index 8a36f1dc057b..72391f4d7dec 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneCapabilitiesTest.java
@@ -33,9 +33,11 @@ public class TimeZoneCapabilitiesTest {
public void testEquals() {
TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
{
TimeZoneCapabilities one = builder1.build();
@@ -57,6 +59,20 @@ public class TimeZoneCapabilitiesTest {
assertEquals(one, two);
}
+ builder2.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
+ {
+ TimeZoneCapabilities one = builder1.build();
+ TimeZoneCapabilities two = builder2.build();
+ assertEquals(one, two);
+ }
+
builder2.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
{
TimeZoneCapabilities one = builder1.build();
@@ -76,12 +92,16 @@ public class TimeZoneCapabilitiesTest {
public void testParcelable() {
TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED);
assertRoundTripParcelable(builder.build());
builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
assertRoundTripParcelable(builder.build());
+ builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
+ assertRoundTripParcelable(builder.build());
+
builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
assertRoundTripParcelable(builder.build());
}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
index ac7e9c437b63..00dc73ed269f 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TimeZoneConfigurationTest.java
@@ -29,8 +29,9 @@ public class TimeZoneConfigurationTest {
@Test
public void testBuilder_copyConstructor() {
- TimeZoneConfiguration.Builder builder1 =
- new TimeZoneConfiguration.Builder().setAutoDetectionEnabled(true);
+ TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true);
TimeZoneConfiguration configuration1 = builder1.build();
TimeZoneConfiguration configuration2 =
@@ -41,16 +42,15 @@ public class TimeZoneConfigurationTest {
@Test
public void testIsComplete() {
- TimeZoneConfiguration incompleteConfiguration =
- new TimeZoneConfiguration.Builder()
- .build();
- assertFalse(incompleteConfiguration.isComplete());
+ TimeZoneConfiguration.Builder builder =
+ new TimeZoneConfiguration.Builder();
+ assertFalse(builder.build().isComplete());
- TimeZoneConfiguration completeConfiguration =
- new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(true)
- .build();
- assertTrue(completeConfiguration.isComplete());
+ builder.setAutoDetectionEnabled(true);
+ assertFalse(builder.build().isComplete());
+
+ builder.setGeoDetectionEnabled(true);
+ assertTrue(builder.build().isComplete());
}
@Test
@@ -122,6 +122,27 @@ public class TimeZoneConfigurationTest {
TimeZoneConfiguration two = builder2.build();
assertEquals(one, two);
}
+
+ builder1.setGeoDetectionEnabled(true);
+ {
+ TimeZoneConfiguration one = builder1.build();
+ TimeZoneConfiguration two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder2.setGeoDetectionEnabled(false);
+ {
+ TimeZoneConfiguration one = builder1.build();
+ TimeZoneConfiguration two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setGeoDetectionEnabled(false);
+ {
+ TimeZoneConfiguration one = builder1.build();
+ TimeZoneConfiguration two = builder2.build();
+ assertEquals(one, two);
+ }
}
@Test
@@ -135,5 +156,11 @@ public class TimeZoneConfigurationTest {
builder.setAutoDetectionEnabled(false);
assertRoundTripParcelable(builder.build());
+
+ builder.setGeoDetectionEnabled(false);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setGeoDetectionEnabled(true);
+ assertRoundTripParcelable(builder.build());
}
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index e06cf945ddaa..51e7287bfd72 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -5596,6 +5596,7 @@ package android.app {
method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public int getSemanticAction();
+ method public boolean isAuthenticationRequired();
method public boolean isContextual();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
@@ -5625,6 +5626,7 @@ package android.app {
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+ method @NonNull public android.app.Notification.Action.Builder setAuthenticationRequired(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 816bcf8f274b..d5f74a86fd94 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -53,8 +53,8 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION;
@VisibleForTesting
- protected WindowMagnificationController mWindowMagnificationController;
- protected final ModeSwitchesController mModeSwitchesController;
+ protected WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+ private final ModeSwitchesController mModeSwitchesController;
private final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
private final CommandQueue mCommandQueue;
@@ -72,6 +72,11 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
Context.ACCESSIBILITY_SERVICE);
mCommandQueue = commandQueue;
mModeSwitchesController = modeSwitchesController;
+ final WindowMagnificationController controller = new WindowMagnificationController(mContext,
+ mHandler, new SfVsyncFrameCallbackProvider(), null,
+ new SurfaceControl.Transaction(), this);
+ mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+ mContext, controller);
}
@Override
@@ -81,9 +86,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
return;
}
mLastConfiguration.setTo(newConfig);
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.onConfigurationChanged(configDiff);
- }
+ mWindowMagnificationAnimationController.onConfigurationChanged(configDiff);
if (mModeSwitchesController != null) {
mModeSwitchesController.onConfigurationChanged(configDiff);
}
@@ -97,39 +100,25 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
@MainThread
void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController == null) {
- mWindowMagnificationController = new WindowMagnificationController(mContext,
- mHandler,
- new SfVsyncFrameCallbackProvider(),
- null, new SurfaceControl.Transaction(),
- this);
- }
- mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
+ mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
}
@MainThread
void setScale(int displayId, float scale) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.setScale(scale);
- }
+ mWindowMagnificationAnimationController.setScale(scale);
}
@MainThread
void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY);
- }
+ mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY);
}
@MainThread
void disableWindowMagnification(int displayId) {
//TODO: b/144080869 support multi-display.
- if (mWindowMagnificationController != null) {
- mWindowMagnificationController.deleteWindowMagnification();
- }
- mWindowMagnificationController = null;
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
new file mode 100644
index 000000000000..ae51623f3dc2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Provides same functionality of {@link WindowMagnificationController}. Some methods run with
+ * the animation.
+ */
+class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener,
+ Animator.AnimatorListener {
+
+ private static final String TAG = "WindowMagnificationBridge";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING})
+ @interface MagnificationState {}
+
+ //The window magnification is disabled.
+ private static final int STATE_DISABLED = 0;
+ //The window magnification is enabled.
+ private static final int STATE_ENABLED = 1;
+ //The window magnification is going to be disabled when the animation is end.
+ private static final int STATE_DISABLING = 2;
+ //The animation is running for enabling the window magnification.
+ private static final int STATE_ENABLING = 3;
+
+ private final WindowMagnificationController mController;
+ private final ValueAnimator mValueAnimator;
+ private final AnimationSpec mStartSpec = new AnimationSpec();
+ private final AnimationSpec mEndSpec = new AnimationSpec();
+ private final Context mContext;
+
+ @MagnificationState
+ private int mState = STATE_DISABLED;
+
+ WindowMagnificationAnimationController(
+ Context context, WindowMagnificationController controller) {
+ this(context, controller, newValueAnimator(context.getResources()));
+ }
+
+ @VisibleForTesting
+ WindowMagnificationAnimationController(Context context,
+ WindowMagnificationController controller, ValueAnimator valueAnimator) {
+ mContext = context;
+ mController = controller;
+ mValueAnimator = valueAnimator;
+ mValueAnimator.addUpdateListener(this);
+ mValueAnimator.addListener(this);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)}
+ * with transition animation. If the window magnification is not enabled, the scale will start
+ * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
+ * {@code STATE_DISABLING}, the animation runs in reverse.
+ *
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged.
+ * @param centerX the screen-relative X coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ * @param centerY the screen-relative Y coordinate around which to center,
+ * or {@link Float#NaN} to leave unchanged.
+ *
+ * @see #onAnimationUpdate(ValueAnimator)
+ */
+ void enableWindowMagnification(float scale, float centerX, float centerY) {
+ if (mState == STATE_ENABLING) {
+ mValueAnimator.cancel();
+ }
+ setupEnableAnimationSpecs(scale, centerX, centerY);
+
+ if (mEndSpec.equals(mStartSpec)) {
+ setState(STATE_ENABLED);
+ } else {
+ if (mState == STATE_DISABLING) {
+ mValueAnimator.reverse();
+ } else {
+ mValueAnimator.start();
+ }
+ setState(STATE_ENABLING);
+ }
+ }
+
+ private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) {
+ final float currentScale = mController.getScale();
+ final float currentCenterX = mController.getCenterX();
+ final float currentCenterY = mController.getCenterY();
+
+ if (mState == STATE_DISABLED) {
+ //We don't need to offset the center during the animation.
+ mStartSpec.set(/* scale*/ 1.0f, centerX, centerY);
+ mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger(
+ R.integer.magnification_default_scale) : scale, centerX, centerY);
+ } else {
+ mStartSpec.set(currentScale, currentCenterX, currentCenterY);
+ mEndSpec.set(Float.isNaN(scale) ? currentScale : scale,
+ Float.isNaN(centerX) ? currentCenterX : centerX,
+ Float.isNaN(centerY) ? currentCenterY : centerY);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = "
+ + mEndSpec);
+ }
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is
+ * running, it has no effect.
+ */
+ void setScale(float scale) {
+ if (mValueAnimator.isRunning()) {
+ return;
+ }
+ mController.setScale(scale);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
+ * animation. If the window magnification is enabling, it runs the animation in reverse.
+ */
+ void deleteWindowMagnification() {
+ if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
+ return;
+ }
+ mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
+ mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN);
+
+ mValueAnimator.reverse();
+ setState(STATE_DISABLING);
+ }
+
+ /**
+ * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
+ * animation is running, it has no effect.
+ * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
+ * current screen pixels.
+ * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
+ * current screen pixels.
+ */
+ void moveWindowMagnifier(float offsetX, float offsetY) {
+ if (mValueAnimator.isRunning()) {
+ return;
+ }
+ mController.moveWindowMagnifier(offsetX, offsetY);
+ }
+
+ void onConfigurationChanged(int configDiff) {
+ mController.onConfigurationChanged(configDiff);
+ }
+
+ private void setState(@MagnificationState int state) {
+ if (DEBUG) {
+ Log.d(TAG, "setState from " + mState + " to " + state);
+ }
+ mState = state;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mState == STATE_DISABLING) {
+ mController.deleteWindowMagnification();
+ setState(STATE_DISABLED);
+ } else if (mState == STATE_ENABLING) {
+ setState(STATE_ENABLED);
+ } else {
+ Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float fract = animation.getAnimatedFraction();
+ final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract;
+ final float centerX =
+ mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract;
+ final float centerY =
+ mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract;
+ mController.enableWindowMagnification(sentScale, centerX, centerY);
+ }
+
+ private static ValueAnimator newValueAnimator(Resources resources) {
+ final ValueAnimator valueAnimator = new ValueAnimator();
+ valueAnimator.setDuration(
+ resources.getInteger(com.android.internal.R.integer.config_longAnimTime));
+ valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
+ valueAnimator.setFloatValues(0.0f, 1.0f);
+ return valueAnimator;
+ }
+
+ private static class AnimationSpec {
+ private float mScale = Float.NaN;
+ private float mCenterX = Float.NaN;
+ private float mCenterY = Float.NaN;
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ final AnimationSpec s = (AnimationSpec) other;
+ return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0);
+ result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0);
+ result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0);
+ return result;
+ }
+
+ void set(float scale, float centerX, float centerY) {
+ mScale = scale;
+ mCenterX = centerX;
+ mCenterY = centerY;
+ }
+
+ @Override
+ public String toString() {
+ return "AnimationSpec{"
+ + "mScale=" + mScale
+ + ", mCenterX=" + mCenterX
+ + ", mCenterY=" + mCenterY
+ + '}';
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 798b751c03ee..494a0f64cea4 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -150,7 +150,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mMirrorViewGeometryVsyncCallback =
l -> {
- if (mMirrorView != null && mMirrorSurface != null) {
+ if (isWindowVisible() && mMirrorSurface != null) {
calculateSourceBounds(mMagnificationFrame, mScale);
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
@@ -203,13 +203,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* @param configDiff a bit mask of the differences between the configurations
*/
void onConfigurationChanged(int configDiff) {
+ if (!isWindowVisible()) {
+ return;
+ }
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
- // TODO(b/145780606): update toggle button UI.
- if (mMirrorView != null) {
- mWm.removeView(mMirrorView);
- createMirrorWindow();
- }
+ mWm.removeView(mMirrorView);
+ createMirrorWindow();
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
}
@@ -502,7 +502,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
/**
* Enables window magnification with specified parameters.
*
- * @param scale the target scale
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
* @param centerX the screen-relative X coordinate around which to center,
* or {@link Float#NaN} to leave unchanged.
* @param centerY the screen-relative Y coordinate around which to center,
@@ -513,10 +513,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
: centerX - mMagnificationFrame.exactCenterX();
final float offsetY = Float.isNaN(centerY) ? 0
: centerY - mMagnificationFrame.exactCenterY();
- mScale = scale;
+ mScale = Float.isNaN(scale) ? mScale : scale;
setMagnificationFrameBoundary();
updateMagnificationFramePosition((int) offsetX, (int) offsetY);
- if (mMirrorView == null) {
+ if (!isWindowVisible()) {
createMirrorWindow();
showControls();
} else {
@@ -527,10 +527,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
/**
* Sets the scale of the magnified region if it's visible.
*
- * @param scale the target scale
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
*/
void setScale(float scale) {
- if (mMirrorView == null || mScale == scale) {
+ if (!isWindowVisible() || mScale == scale) {
return;
}
enableWindowMagnification(scale, Float.NaN, Float.NaN);
@@ -552,4 +552,35 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
modifyWindowMagnification(mTransaction);
}
}
+
+ /**
+ * Gets the scale.
+ * @return {@link Float#NaN} if the window is invisible.
+ */
+ float getScale() {
+ return isWindowVisible() ? mScale : Float.NaN;
+ }
+
+ /**
+ * Returns the screen-relative X coordinate of the center of the magnified bounds.
+ *
+ * @return the X coordinate. {@link Float#NaN} if the window is invisible.
+ */
+ float getCenterX() {
+ return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN;
+ }
+
+ /**
+ * Returns the screen-relative Y coordinate of the center of the magnified bounds.
+ *
+ * @return the Y coordinate. {@link Float#NaN} if the window is invisible.
+ */
+ float getCenterY() {
+ return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN;
+ }
+
+ //The window is visible when it is existed.
+ private boolean isWindowVisible() {
+ return mMirrorView != null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 7e5b42653210..93a8df41c673 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -25,7 +25,9 @@ public class AppOpItem {
private int mUid;
private String mPackageName;
private long mTimeStarted;
- private String mState;
+ private StringBuilder mState;
+ // This is only used for items with mCode == AppOpsManager.OP_RECORD_AUDIO
+ private boolean mSilenced;
public AppOpItem(int code, int uid, String packageName, long timeStarted) {
this.mCode = code;
@@ -36,9 +38,8 @@ public class AppOpItem {
.append("AppOpItem(")
.append("Op code=").append(code).append(", ")
.append("UID=").append(uid).append(", ")
- .append("Package name=").append(packageName)
- .append(")")
- .toString();
+ .append("Package name=").append(packageName).append(", ")
+ .append("Paused=");
}
public int getCode() {
@@ -57,8 +58,16 @@ public class AppOpItem {
return mTimeStarted;
}
+ public void setSilenced(boolean silenced) {
+ mSilenced = silenced;
+ }
+
+ public boolean isSilenced() {
+ return mSilenced;
+ }
+
@Override
public String toString() {
- return mState;
+ return mState.append(mSilenced).append(")").toString();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 6512624f5064..8187a2235c0a 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -19,6 +19,8 @@ package com.android.systemui.appops;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.media.AudioRecordingConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -63,6 +65,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private static final boolean DEBUG = false;
private final AppOpsManager mAppOps;
+ private final AudioManager mAudioManager;
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
@@ -73,6 +76,9 @@ public class AppOpsControllerImpl implements AppOpsController,
private final List<AppOpItem> mActiveItems = new ArrayList<>();
@GuardedBy("mNotedItems")
private final List<AppOpItem> mNotedItems = new ArrayList<>();
+ @GuardedBy("mActiveItems")
+ private final SparseArray<ArrayList<AudioRecordingConfiguration>> mRecordingsByUid =
+ new SparseArray<>();
protected static final int[] OPS = new int[] {
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
@@ -88,7 +94,8 @@ public class AppOpsControllerImpl implements AppOpsController,
Context context,
@Background Looper bgLooper,
DumpManager dumpManager,
- PermissionFlagsCache cache
+ PermissionFlagsCache cache,
+ AudioManager audioManager
) {
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mFlagsCache = cache;
@@ -97,6 +104,7 @@ public class AppOpsControllerImpl implements AppOpsController,
for (int i = 0; i < numOps; i++) {
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
+ mAudioManager = audioManager;
dumpManager.registerDumpable(TAG, this);
}
@@ -111,12 +119,19 @@ public class AppOpsControllerImpl implements AppOpsController,
if (listening) {
mAppOps.startWatchingActive(OPS, this);
mAppOps.startWatchingNoted(OPS, this);
+ mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
+ mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
+ mAudioManager.getActiveRecordingConfigurations()));
+
} else {
mAppOps.stopWatchingActive(this);
mAppOps.stopWatchingNoted(this);
+ mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
+
mBGHandler.removeCallbacksAndMessages(null); // null removes all
synchronized (mActiveItems) {
mActiveItems.clear();
+ mRecordingsByUid.clear();
}
synchronized (mNotedItems) {
mNotedItems.clear();
@@ -189,9 +204,12 @@ public class AppOpsControllerImpl implements AppOpsController,
AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName);
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
+ if (code == AppOpsManager.OP_RECORD_AUDIO) {
+ item.setSilenced(isAnyRecordingPausedLocked(uid));
+ }
mActiveItems.add(item);
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
- return true;
+ return !item.isSilenced();
} else if (item != null && !active) {
mActiveItems.remove(item);
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
@@ -215,7 +233,7 @@ public class AppOpsControllerImpl implements AppOpsController,
active = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null;
}
if (!active) {
- notifySuscribers(code, uid, packageName, false);
+ notifySuscribersWorker(code, uid, packageName, false);
}
}
@@ -324,7 +342,7 @@ public class AppOpsControllerImpl implements AppOpsController,
AppOpItem item = mActiveItems.get(i);
if ((userId == UserHandle.USER_ALL
|| UserHandle.getUserId(item.getUid()) == userId)
- && isUserVisible(item)) {
+ && isUserVisible(item) && !item.isSilenced()) {
list.add(item);
}
}
@@ -343,6 +361,10 @@ public class AppOpsControllerImpl implements AppOpsController,
return list;
}
+ private void notifySuscribers(int code, int uid, String packageName, boolean active) {
+ mBGHandler.post(() -> notifySuscribersWorker(code, uid, packageName, active));
+ }
+
@Override
public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
if (DEBUG) {
@@ -360,7 +382,7 @@ public class AppOpsControllerImpl implements AppOpsController,
// If active is false, we only send the update if the op is not actively noted (prevent
// early removal)
if (!alsoNoted) {
- mBGHandler.post(() -> notifySuscribers(code, uid, packageName, active));
+ notifySuscribers(code, uid, packageName, active);
}
}
@@ -378,11 +400,11 @@ public class AppOpsControllerImpl implements AppOpsController,
alsoActive = getAppOpItemLocked(mActiveItems, code, uid, packageName) != null;
}
if (!alsoActive) {
- mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true));
+ notifySuscribers(code, uid, packageName, true);
}
}
- private void notifySuscribers(int code, int uid, String packageName, boolean active) {
+ private void notifySuscribersWorker(int code, int uid, String packageName, boolean active) {
if (mCallbacksByCode.contains(code) && isUserVisible(code, uid, packageName)) {
if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
@@ -408,6 +430,61 @@ public class AppOpsControllerImpl implements AppOpsController,
}
+ private boolean isAnyRecordingPausedLocked(int uid) {
+ List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid);
+ if (configs == null) return false;
+ int configsNum = configs.size();
+ for (int i = 0; i < configsNum; i++) {
+ AudioRecordingConfiguration config = configs.get(i);
+ if (config.isClientSilenced()) return true;
+ }
+ return false;
+ }
+
+ private void updateRecordingPausedStatus() {
+ synchronized (mActiveItems) {
+ int size = mActiveItems.size();
+ for (int i = 0; i < size; i++) {
+ AppOpItem item = mActiveItems.get(i);
+ if (item.getCode() == AppOpsManager.OP_RECORD_AUDIO) {
+ boolean paused = isAnyRecordingPausedLocked(item.getUid());
+ if (item.isSilenced() != paused) {
+ item.setSilenced(paused);
+ notifySuscribers(
+ item.getCode(),
+ item.getUid(),
+ item.getPackageName(),
+ !item.isSilenced()
+ );
+ }
+ }
+ }
+ }
+ }
+
+ private AudioManager.AudioRecordingCallback mAudioRecordingCallback =
+ new AudioManager.AudioRecordingCallback() {
+ @Override
+ public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
+ synchronized (mActiveItems) {
+ mRecordingsByUid.clear();
+ final int recordingsCount = configs.size();
+ for (int i = 0; i < recordingsCount; i++) {
+ AudioRecordingConfiguration recording = configs.get(i);
+
+ ArrayList<AudioRecordingConfiguration> recordings = mRecordingsByUid.get(
+ recording.getClientUid());
+ if (recordings == null) {
+ recordings = new ArrayList<>();
+ mRecordingsByUid.put(recording.getClientUid(), recordings);
+ }
+ recordings.add(recording);
+ }
+ }
+ updateRecordingPausedStatus();
+ }
+ };
+
protected class H extends Handler {
H(Looper looper) {
super(looper);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8a51c8515852..e77e499223aa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -44,6 +44,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
@@ -97,6 +98,7 @@ class MediaDataManager(
dumpManager: DumpManager,
mediaTimeoutListener: MediaTimeoutListener,
mediaResumeListener: MediaResumeListener,
+ private val activityStarter: ActivityStarter,
private var useMediaResumption: Boolean,
private val useQsMediaPlayer: Boolean
) : Dumpable {
@@ -113,10 +115,11 @@ class MediaDataManager(
dumpManager: DumpManager,
broadcastDispatcher: BroadcastDispatcher,
mediaTimeoutListener: MediaTimeoutListener,
- mediaResumeListener: MediaResumeListener
+ mediaResumeListener: MediaResumeListener,
+ activityStarter: ActivityStarter
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
- Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context))
+ activityStarter, Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context))
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -403,10 +406,13 @@ class MediaDataManager(
}
val runnable = if (action.actionIntent != null) {
Runnable {
- try {
- action.actionIntent.send()
- } catch (e: PendingIntent.CanceledException) {
- Log.d(TAG, "Intent canceled", e)
+ if (action.isAuthenticationRequired()) {
+ activityStarter.dismissKeyguardThenExecute ({
+ var result = sendPendingIntent(action.actionIntent)
+ result
+ }, {}, true)
+ } else {
+ sendPendingIntent(action.actionIntent)
}
}
} else {
@@ -449,6 +455,15 @@ class MediaDataManager(
return null
}
+ private fun sendPendingIntent(intent: PendingIntent): Boolean {
+ return try {
+ intent.send()
+ true
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ false
+ }
+ }
/**
* Load a bitmap from a URI
* @param uri the uri to load
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 01670285c0f4..f1c8b0cf0e42 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -186,20 +186,23 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private class PipManagerPinnedStackListener extends PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- if (mState == STATE_PIP) {
- if (mImeVisible != imeVisible) {
- if (imeVisible) {
- // Save the IME height adjustment, and offset to not occlude the IME
- mPipBounds.offset(0, -imeHeight);
- mImeHeightAdjustment = imeHeight;
- } else {
- // Apply the inverse adjustment when the IME is hidden
- mPipBounds.offset(0, mImeHeightAdjustment);
+ mHandler.post(() -> {
+ mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ if (mState == STATE_PIP) {
+ if (mImeVisible != imeVisible) {
+ if (imeVisible) {
+ // Save the IME height adjustment, and offset to not occlude the IME
+ mPipBounds.offset(0, -imeHeight);
+ mImeHeightAdjustment = imeHeight;
+ } else {
+ // Apply the inverse adjustment when the IME is hidden
+ mPipBounds.offset(0, mImeHeightAdjustment);
+ }
+ mImeVisible = imeVisible;
+ resizePinnedStack(STATE_PIP);
}
- mImeVisible = imeVisible;
- resizePinnedStack(STATE_PIP);
}
- }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index d2aaaede3f4b..255513a31c75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs.tileimpl;
+import static androidx.lifecycle.Lifecycle.State.CREATED;
import static androidx.lifecycle.Lifecycle.State.DESTROYED;
import static androidx.lifecycle.Lifecycle.State.RESUMED;
import static androidx.lifecycle.Lifecycle.State.STARTED;
@@ -173,6 +174,7 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
mState = newTileState();
mTmpState = newTileState();
+ mUiHandler.post(() -> mLifecycle.setCurrentState(CREATED));
}
protected final void resetStates() {
@@ -453,6 +455,9 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
if (DEBUG) Log.d(TAG, "handleSetListening true");
handleSetListening(listening);
mUiHandler.post(() -> {
+ // This tile has been destroyed, the state should not change anymore and we
+ // should not refresh it anymore.
+ if (mLifecycle.getCurrentState().equals(DESTROYED)) return;
mLifecycle.setCurrentState(RESUMED);
refreshState(); // Ensure we get at least one refresh after listening.
});
@@ -461,7 +466,11 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
if (mListeners.remove(listener) && mListeners.size() == 0) {
if (DEBUG) Log.d(TAG, "handleSetListening false");
handleSetListening(listening);
- mUiHandler.post(() -> mLifecycle.setCurrentState(STARTED));
+ mUiHandler.post(() -> {
+ // This tile has been destroyed, the state should not change anymore.
+ if (mLifecycle.getCurrentState().equals(DESTROYED)) return;
+ mLifecycle.setCurrentState(STARTED);
+ });
}
}
updateIsFullQs();
@@ -488,11 +497,14 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
mQSLogger.logTileDestroyed(mTileSpec, "Handle destroy");
if (mListeners.size() != 0) {
handleSetListening(false);
+ mListeners.clear();
}
mCallbacks.clear();
mHandler.removeCallbacksAndMessages(null);
// This will force it to be removed from all controllers that may have it registered.
- mLifecycle.setCurrentState(DESTROYED);
+ mUiHandler.post(() -> {
+ mLifecycle.setCurrentState(DESTROYED);
+ });
}
protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 6b023c07b1a6..95867957f648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -161,7 +161,9 @@ public class NotificationRemoteInputManager implements Dumpable {
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
- return mCallback.handleRemoteViewClick(view, pendingIntent, () -> {
+ Notification.Action action = getActionFromView(view, entry, pendingIntent);
+ return mCallback.handleRemoteViewClick(view, pendingIntent,
+ action == null ? false : action.isAuthenticationRequired(), () -> {
Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
options.second.setLaunchWindowingMode(
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
@@ -170,47 +172,56 @@ public class NotificationRemoteInputManager implements Dumpable {
});
}
- private void logActionClick(
- View view,
- NotificationEntry entry,
- PendingIntent actionIntent) {
+ private @Nullable Notification.Action getActionFromView(View view,
+ NotificationEntry entry, PendingIntent actionIntent) {
Integer actionIndex = (Integer)
view.getTag(com.android.internal.R.id.notification_action_index_tag);
if (actionIndex == null) {
- // Custom action button, not logging.
- return;
+ return null;
}
- ViewParent parent = view.getParent();
if (entry == null) {
Log.w(TAG, "Couldn't determine notification for click.");
- return;
- }
- StatusBarNotification statusBarNotification = entry.getSbn();
- String key = statusBarNotification.getKey();
- int buttonIndex = -1;
- // If this is a default template, determine the index of the button.
- if (view.getId() == com.android.internal.R.id.action0 &&
- parent != null && parent instanceof ViewGroup) {
- ViewGroup actionGroup = (ViewGroup) parent;
- buttonIndex = actionGroup.indexOfChild(view);
+ return null;
}
- final int count = mEntryManager.getActiveNotificationsCount();
- final int rank = mEntryManager
- .getActiveNotificationUnfiltered(key).getRanking().getRank();
// Notification may be updated before this function is executed, and thus play safe
// here and verify that the action object is still the one that where the click happens.
+ StatusBarNotification statusBarNotification = entry.getSbn();
Notification.Action[] actions = statusBarNotification.getNotification().actions;
if (actions == null || actionIndex >= actions.length) {
Log.w(TAG, "statusBarNotification.getNotification().actions is null or invalid");
- return;
+ return null ;
}
final Notification.Action action =
statusBarNotification.getNotification().actions[actionIndex];
if (!Objects.equals(action.actionIntent, actionIntent)) {
Log.w(TAG, "actionIntent does not match");
+ return null;
+ }
+ return action;
+ }
+
+ private void logActionClick(
+ View view,
+ NotificationEntry entry,
+ PendingIntent actionIntent) {
+ Notification.Action action = getActionFromView(view, entry, actionIntent);
+ if (action == null) {
return;
}
+ ViewParent parent = view.getParent();
+ String key = entry.getSbn().getKey();
+ int buttonIndex = -1;
+ // If this is a default template, determine the index of the button.
+ if (view.getId() == com.android.internal.R.id.action0 &&
+ parent != null && parent instanceof ViewGroup) {
+ ViewGroup actionGroup = (ViewGroup) parent;
+ buttonIndex = actionGroup.indexOfChild(view);
+ }
+ final int count = mEntryManager.getActiveNotificationsCount();
+ final int rank = mEntryManager
+ .getActiveNotificationUnfiltered(key).getRanking().getRank();
+
NotificationVisibility.NotificationLocation location =
NotificationLogger.getNotificationLocation(
mEntryManager.getActiveNotificationUnfiltered(key));
@@ -813,11 +824,12 @@ public class NotificationRemoteInputManager implements Dumpable {
*
* @param view
* @param pendingIntent
+ * @param appRequestedAuth
* @param defaultHandler
* @return true iff the click was handled
*/
boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
- ClickHandler defaultHandler);
+ boolean appRequestedAuth, ClickHandler defaultHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 8cb54eef01b4..e42c3dc4f589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -284,13 +284,22 @@ public class PhoneStatusBarPolicy
mResources.getString(R.string.accessibility_data_saver_on));
mIconController.setIconVisibility(mSlotDataSaver, false);
+
// privacy items
+ String microphoneString = mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId());
+ String microphoneDesc = mResources.getString(
+ R.string.ongoing_privacy_chip_content_multiple_apps, microphoneString);
mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(),
- mResources.getString(PrivacyType.TYPE_MICROPHONE.getNameId()));
+ microphoneDesc);
mIconController.setIconVisibility(mSlotMicrophone, false);
+
+ String cameraString = mResources.getString(PrivacyType.TYPE_CAMERA.getNameId());
+ String cameraDesc = mResources.getString(
+ R.string.ongoing_privacy_chip_content_multiple_apps, cameraString);
mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(),
- mResources.getString(PrivacyType.TYPE_CAMERA.getNameId()));
+ cameraDesc);
mIconController.setIconVisibility(mSlotCamera, false);
+
mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
mResources.getString(R.string.accessibility_location_active));
mIconController.setIconVisibility(mSlotLocation, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 72395e68ff07..ac69d9c32c93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -244,9 +244,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
@Override
public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+ boolean appRequestedAuth,
NotificationRemoteInputManager.ClickHandler defaultHandler) {
final boolean isActivity = pendingIntent.isActivity();
- if (isActivity) {
+ if (isActivity || appRequestedAuth) {
mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent);
final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(
pendingIntent.getIntent(), mLockscreenUserManager.getCurrentUserId());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index fbc8e9d8de79..ac567e0ae67d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -47,6 +48,7 @@ import org.mockito.MockitoAnnotations;
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class IWindowMagnificationConnectionTest extends SysuiTestCase {
private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
@@ -57,7 +59,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
@Mock
private IWindowMagnificationConnectionCallback mConnectionCallback;
@Mock
- private WindowMagnificationController mWindowMagnificationController;
+ private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@Mock
private ModeSwitchesController mModeSwitchesController;
private IWindowMagnificationConnection mIWindowMagnificationConnection;
@@ -74,7 +76,8 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
any(IWindowMagnificationConnection.class));
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController);
- mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController;
+ mWindowMagnification.mWindowMagnificationAnimationController =
+ mWindowMagnificationAnimationController;
mWindowMagnification.requestWindowMagnificationConnection(true);
assertNotNull(mIWindowMagnificationConnection);
mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback);
@@ -86,7 +89,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
Float.NaN);
waitForIdleSync();
- verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN,
+ verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
Float.NaN);
}
@@ -99,7 +102,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
waitForIdleSync();
- verify(mWindowMagnificationController).deleteWindowMagnification();
+ verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
}
@Test
@@ -107,7 +110,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f);
waitForIdleSync();
- verify(mWindowMagnificationController).setScale(3.0f);
+ verify(mWindowMagnificationAnimationController).setScale(3.0f);
}
@Test
@@ -115,7 +118,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f);
waitForIdleSync();
- verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f);
+ verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
new file mode 100644
index 000000000000..b7c198e53cfa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.animation.ValueAnimator;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.view.SurfaceControl;
+import android.view.animation.AccelerateInterpolator;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+
+@MediumTest
+@RunWith(AndroidTestingRunner.class)
+public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
+
+ private static final float DEFAULT_SCALE = 3.0f;
+ private static final float DEFAULT_CENTER_X = 400.0f;
+ private static final float DEFAULT_CENTER_Y = 500.0f;
+ // The duration couldn't too short, otherwise the ValueAnimator won't work in expectation.
+ private static final long ANIMATION_DURATION_MS = 200;
+
+ private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
+ private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
+ private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0);
+ private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class);
+ private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class);
+ private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class);
+
+ @Mock
+ Handler mHandler;
+ @Mock
+ SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
+ @Mock
+ WindowMagnifierCallback mWindowMagnifierCallback;
+
+ private SpyWindowMagnificationController mController;
+ private WindowMagnificationController mSpyController;
+ private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
+ private Instrumentation mInstrumentation;
+ private long mWaitingAnimationPeriod;
+ private long mWaitIntermediateAnimationPeriod;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50;
+ mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
+ mController = new SpyWindowMagnificationController(mContext, mHandler,
+ mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
+ mWindowMagnifierCallback);
+ mSpyController = mController.getSpyController();
+ mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
+ mContext, mController, newValueAnimator());
+ }
+
+ @Test
+ public void enableWindowMagnification_disabled_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(
+ mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verifyStartValue(mScaleCaptor, 1.0f);
+ verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X);
+ verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y);
+ verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ }
+
+ @Test
+ public void enableWindowMagnification_enabling_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ final float targetScale = DEFAULT_SCALE + 1.0f;
+ final float targetCenterX = DEFAULT_CENTER_X + 100;
+ final float targetCenterY = DEFAULT_CENTER_Y + 100;
+
+ mInstrumentation.runOnMainSync(() -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verifyStartValue(mScaleCaptor, mCurrentScale.get());
+ verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
+ verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
+ verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ }
+
+ @Test
+ public void enableWindowMagnification_disabling_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+ final float targetScale = DEFAULT_SCALE + 1.0f;
+ final float targetCenterX = DEFAULT_CENTER_X + 100;
+ final float targetCenterY = DEFAULT_CENTER_Y + 100;
+
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+ targetCenterX, targetCenterY);
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(
+ mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ //Animating in reverse, so we only check if the start values are greater than current.
+ assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get());
+ assertEquals(targetScale, mScaleCaptor.getValue(), 0f);
+ assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get());
+ assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f);
+ assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get());
+ assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f);
+ verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
+ }
+
+ @Test
+ public void enableWindowMagnificationWithSameScale_doNothing() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(),
+ anyFloat());
+ }
+
+ @Test
+ public void setScale_enabled_expectedScale() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
+
+ verify(mSpyController).setScale(DEFAULT_SCALE + 1);
+ verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ }
+
+ @Test
+ public void deleteWindowMagnification_enabled_expectedStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+ verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
+ verifyStartValue(mCenterXCaptor, Float.NaN);
+ verifyStartValue(mCenterYCaptor, Float.NaN);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void deleteWindowMagnification_disabled_doNothing() {
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ Mockito.verifyNoMoreInteractions(mSpyController);
+ }
+
+ @Test
+ public void deleteWindowMagnification_enabling_checkStartAndEndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+
+ //It just reverse the animation, so we don't need to wait the whole duration.
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
+ mCurrentScale.set(mController.getScale());
+ mCurrentCenterX.set(mController.getCenterX());
+ mCurrentCenterY.set(mController.getCenterY());
+ });
+ SystemClock.sleep(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+
+ //The animation is in verse, so we only check the start values should no be greater than
+ // the current one.
+ assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get());
+ assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
+ verifyStartValue(mCenterXCaptor, Float.NaN);
+ verifyStartValue(mCenterYCaptor, Float.NaN);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void deleteWindowMagnification_disabling_checkStartAndValues() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+ deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod);
+
+ deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
+ mCenterXCaptor.capture(), mCenterYCaptor.capture());
+ verify(mSpyController).deleteWindowMagnification();
+ assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
+ verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
+ }
+
+ @Test
+ public void moveWindowMagnifier_enabled() {
+ enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod);
+
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
+
+ verify(mSpyController).moveWindowMagnifier(100f, 200f);
+ verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
+ }
+
+ @Test
+ public void onConfigurationChanged_passThrough() {
+ mWindowMagnificationAnimationController.onConfigurationChanged(100);
+
+ verify(mSpyController).onConfigurationChanged(100);
+ }
+ private void verifyFinalSpec(float expectedScale, float expectedCenterX,
+ float expectedCenterY) {
+ assertEquals(expectedScale, mController.getScale(), 0f);
+ assertEquals(expectedCenterX, mController.getCenterX(), 0f);
+ assertEquals(expectedCenterY, mController.getCenterY(), 0f);
+ }
+
+ private void enableWindowMagnificationAndWaitAnimating(long duration) {
+ mInstrumentation.runOnMainSync(
+ () -> {
+ Mockito.reset(mSpyController);
+ mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+ DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+ });
+ SystemClock.sleep(duration);
+ }
+
+ private void deleteWindowMagnificationAndWaitAnimating(long duration) {
+ mInstrumentation.runOnMainSync(
+ () -> {
+ resetMockObjects();
+ mWindowMagnificationAnimationController.deleteWindowMagnification();
+ });
+ SystemClock.sleep(duration);
+ }
+
+ private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
+ assertEquals(startValue, captor.getAllValues().get(0), 0f);
+ }
+
+ private void resetMockObjects() {
+ Mockito.reset(mSpyController);
+ }
+
+ /**
+ * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it
+ * directly.
+ */
+ private static class SpyWindowMagnificationController extends WindowMagnificationController {
+ private WindowMagnificationController mSpyController;
+
+ SpyWindowMagnificationController(Context context, Handler handler,
+ SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
+ MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
+ WindowMagnifierCallback callback) {
+ super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
+ callback);
+ mSpyController = Mockito.mock(WindowMagnificationController.class);
+ }
+
+ WindowMagnificationController getSpyController() {
+ return mSpyController;
+ }
+
+ @Override
+ void enableWindowMagnification(float scale, float centerX, float centerY) {
+ super.enableWindowMagnification(scale, centerX, centerY);
+ mSpyController.enableWindowMagnification(scale, centerX, centerY);
+ }
+
+ @Override
+ void deleteWindowMagnification() {
+ super.deleteWindowMagnification();
+ mSpyController.deleteWindowMagnification();
+ }
+
+ @Override
+ void moveWindowMagnifier(float offsetX, float offsetY) {
+ super.moveWindowMagnifier(offsetX, offsetX);
+ mSpyController.moveWindowMagnifier(offsetX, offsetY);
+ }
+
+ @Override
+ void setScale(float scale) {
+ super.setScale(scale);
+ mSpyController.setScale(scale);
+ }
+
+ @Override
+ void onConfigurationChanged(int configDiff) {
+ super.onConfigurationChanged(configDiff);
+ mSpyController.onConfigurationChanged(configDiff);
+ }
+
+ }
+
+ private static ValueAnimator newValueAnimator() {
+ final ValueAnimator valueAnimator = new ValueAnimator();
+ valueAnimator.setDuration(ANIMATION_DURATION_MS);
+ valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f));
+ valueAnimator.setFloatValues(0.0f, 1.0f);
+ return valueAnimator;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 2007fbb8fc6c..f1f394e70689 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.accessibility;
import static android.view.Choreographer.FrameCallback;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
@@ -26,8 +27,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
+import android.view.Display;
+import android.view.Surface;
import android.view.SurfaceControl;
import androidx.test.InstrumentationRegistry;
@@ -41,6 +46,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@@ -57,12 +63,14 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
WindowMagnifierCallback mWindowMagnifierCallback;
@Mock
SurfaceControl.Transaction mTransaction;
+ private Context mContext;
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mContext = Mockito.spy(getContext());
mInstrumentation = InstrumentationRegistry.getInstrumentation();
doAnswer(invocation -> {
FrameCallback callback = invocation.getArgument(0);
@@ -73,8 +81,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
when(mTransaction.remove(any())).thenReturn(mTransaction);
when(mTransaction.setGeometry(any(), any(), any(),
anyInt())).thenReturn(mTransaction);
-
- mWindowMagnificationController = new WindowMagnificationController(getContext(),
+ mWindowMagnificationController = new WindowMagnificationController(mContext,
mHandler, mSfVsyncFrameProvider,
mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
verify(mMirrorWindowControl).setWindowDelegate(
@@ -83,9 +90,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
@After
public void tearDown() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.deleteWindowMagnification();
- });
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.deleteWindowMagnification());
}
@Test
@@ -121,4 +127,27 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
}
+
+ @Test
+ public void setScale_enabled_expectedValue() {
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN));
+
+ mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
+
+ assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
+ }
+
+ @Test
+ public void onConfigurationChanged_disabled_withoutException() {
+ Display display = Mockito.spy(mContext.getDisplay());
+ when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+ when(mContext.getDisplay()).thenReturn(display);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
+ });
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 41360130ac65..936558bca2d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -26,6 +26,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
@@ -45,6 +46,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class WindowMagnificationTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 4fdc06e64e2c..8f082c15df36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -27,6 +27,9 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,6 +37,8 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.media.AudioRecordingConfiguration;
import android.os.Looper;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
@@ -47,9 +52,11 @@ import com.android.systemui.dump.DumpManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
import java.util.List;
@SmallTest
@@ -73,6 +80,12 @@ public class AppOpsControllerTest extends SysuiTestCase {
private PermissionFlagsCache mFlagsCache;
@Mock
private PackageManager mPackageManager;
+ @Mock(stubOnly = true)
+ private AudioManager mAudioManager;
+ @Mock(stubOnly = true)
+ private AudioManager.AudioRecordingCallback mRecordingCallback;
+ @Mock(stubOnly = true)
+ private AudioRecordingConfiguration mPausedMockRecording;
private AppOpsControllerImpl mController;
private TestableLooper mTestableLooper;
@@ -94,11 +107,20 @@ public class AppOpsControllerTest extends SysuiTestCase {
when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
eq(TEST_UID_NON_USER_SENSITIVE))).thenReturn(0);
+ doAnswer((invocation) -> mRecordingCallback = invocation.getArgument(0))
+ .when(mAudioManager).registerAudioRecordingCallback(any(), any());
+ when(mPausedMockRecording.getClientUid()).thenReturn(TEST_UID);
+ when(mPausedMockRecording.isClientSilenced()).thenReturn(true);
+
+ when(mAudioManager.getActiveRecordingConfigurations())
+ .thenReturn(List.of(mPausedMockRecording));
+
mController = new AppOpsControllerImpl(
mContext,
mTestableLooper.getLooper(),
mDumpManager,
- mFlagsCache
+ mFlagsCache,
+ mAudioManager
);
}
@@ -363,6 +385,89 @@ public class AppOpsControllerTest extends SysuiTestCase {
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
}
+ @Test
+ public void testPausedRecordingIsRetrievedOnCreation() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback, never())
+ .onActiveStateChanged(anyInt(), anyInt(), anyString(), anyBoolean());
+ }
+
+ @Test
+ public void testPausedRecordingFilteredOut() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ assertTrue(mController.getActiveAppOps().isEmpty());
+ }
+
+ @Test
+ public void testOnlyRecordAudioPaused() {
+ mController.addCallback(new int[]{
+ AppOpsManager.OP_RECORD_AUDIO,
+ AppOpsManager.OP_CAMERA
+ }, mCallback);
+ mTestableLooper.processAllMessages();
+
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true);
+ List<AppOpItem> list = mController.getActiveAppOps();
+
+ assertEquals(1, list.size());
+ assertEquals(AppOpsManager.OP_CAMERA, list.get(0).getCode());
+ }
+
+ @Test
+ public void testUnpausedRecordingSentActive() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+
+ mTestableLooper.processAllMessages();
+ mRecordingCallback.onRecordingConfigChanged(Collections.emptyList());
+
+ mTestableLooper.processAllMessages();
+
+ verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+ }
+
+ @Test
+ public void testAudioPausedSentInactive() {
+ mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+ mTestableLooper.processAllMessages();
+ mController.onOpActiveChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ mTestableLooper.processAllMessages();
+
+ AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class);
+ when(mockARC.getClientUid()).thenReturn(TEST_UID_OTHER);
+ when(mockARC.isClientSilenced()).thenReturn(true);
+
+ mRecordingCallback.onRecordingConfigChanged(List.of(mockARC));
+ mTestableLooper.processAllMessages();
+
+ InOrder inOrder = inOrder(mCallback);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
+ inOrder.verify(mCallback).onActiveStateChanged(
+ AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, false);
+ }
+
private class TestHandler extends AppOpsControllerImpl.H {
TestHandler(Looper looper) {
mController.super(looper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 3789e6ef1f65..a4ebe1ff2a4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -13,6 +13,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
@@ -58,6 +59,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Mock lateinit var mediaTimeoutListener: MediaTimeoutListener
@Mock lateinit var mediaResumeListener: MediaResumeListener
@Mock lateinit var pendingIntent: PendingIntent
+ @Mock lateinit var activityStarter: ActivityStarter
@JvmField @Rule val mockito = MockitoJUnit.rule()
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@@ -68,8 +70,8 @@ class MediaDataManagerTest : SysuiTestCase() {
backgroundExecutor = FakeExecutor(FakeSystemClock())
mediaDataManager = MediaDataManager(context, backgroundExecutor, foregroundExecutor,
mediaControllerFactory, broadcastDispatcher, dumpManager,
- mediaTimeoutListener, mediaResumeListener, useMediaResumption = true,
- useQsMediaPlayer = true)
+ mediaTimeoutListener, mediaResumeListener, activityStarter,
+ useMediaResumption = true, useQsMediaPlayer = true)
session = MediaSession(context, "MediaDataManagerTestSession")
mediaNotification = SbnBuilder().run {
setPkg(PACKAGE_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index bdb7166f5db1..c8e1a74d969f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -78,7 +78,7 @@ import javax.inject.Provider;
@RunWith(AndroidTestingRunner.class)
@SmallTest
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
public class QSTileHostTest extends SysuiTestCase {
private static String MOCK_STATE_STRING = "MockState";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index c2579dd46e78..3aa40dec1fad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -53,7 +53,7 @@ import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
class CustomTileTest : SysuiTestCase() {
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index cccb65d11228..61a0d6c17eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -244,6 +244,8 @@ public class QSTileImplTest extends SysuiTestCase {
assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
mTile.handleDestroy();
+ mTestableLooper.processAllMessages();
+
assertEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
}
@@ -298,6 +300,25 @@ public class QSTileImplTest extends SysuiTestCase {
assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
}
+ @Test
+ public void testRefreshStateAfterDestroyedDoesNotCrash() {
+ mTile.destroy();
+ mTile.refreshState();
+
+ mTestableLooper.processAllMessages();
+ }
+
+ @Test
+ public void testSetListeningAfterDestroyedDoesNotCrash() {
+ Object o = new Object();
+ mTile.destroy();
+
+ mTile.setListening(o, true);
+ mTile.setListening(o, false);
+
+ mTestableLooper.processAllMessages();
+ }
+
private void assertEvent(UiEventLogger.UiEventEnum eventType,
UiEventLoggerFake.FakeUiEvent fakeEvent) {
assertEquals(eventType.getId(), fakeEvent.eventId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index f70106a64968..2006a75c0e16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -38,7 +38,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
class BatterySaverTileTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 8ece62281f77..5d14898cdd2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -58,7 +58,7 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CastTileTest extends SysuiTestCase {
diff --git a/services/Android.bp b/services/Android.bp
index ef52c2aff002..b348b91a1bd7 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -156,14 +156,10 @@ droidstubs {
java_library {
name: "android_system_server_stubs_current",
- defaults: ["android_stubs_dists_default"],
srcs: [":services-stubs.sources"],
installable: false,
static_libs: ["android_module_lib_stubs_current"],
sdk_version: "none",
system_modules: "none",
java_version: "1.8",
- dist: {
- dir: "apistubs/android/system-server",
- },
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index bd25f2bea881..3ee5b28ee338 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -25,10 +25,12 @@ import static java.util.Arrays.copyOfRange;
import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Point;
import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
+import android.view.Display;
import android.view.MotionEvent;
import com.android.internal.annotations.VisibleForTesting;
@@ -90,6 +92,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate;
private final int mDisplayId;
+ private final Context mContext;
+ private final Point mTempPoint = new Point();
private final Queue<MotionEvent> mDebugOutputEventHistory;
@@ -107,7 +111,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
Slog.i(LOG_TAG,
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
}
-
+ mContext = context;
mWindowMagnificationMgr = windowMagnificationMgr;
mDetectShortcutTrigger = detectShortcutTrigger;
mDisplayId = displayId;
@@ -184,7 +188,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
if (!mDetectShortcutTrigger) {
return;
}
- toggleMagnification(Float.NaN, Float.NaN);
+ final Point screenSize = mTempPoint;
+ getScreenSize(mTempPoint);
+ toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f);
+ }
+
+ private void getScreenSize(Point outSize) {
+ final Display display = mContext.getDisplay();
+ display.getRealSize(outSize);
}
@Override
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 59ac09ca2f3d..32d02fb17983 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -114,9 +114,6 @@ public class VibratorService extends IVibratorService.Stub
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
new VibrationAttributes.Builder().build();
- // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
- private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
-
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
// adjustment is defined as the delta between the default intensity level and the user selected
// intensity level. It's important that we apply the scaling on the delta between the two so
@@ -187,8 +184,8 @@ public class VibratorService extends IVibratorService.Stub
static native int[] vibratorGetSupportedEffects(long controllerPtr);
- static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
- boolean withCallback);
+ static native long vibratorPerformEffect(
+ long controllerPtr, long effect, long strength, Vibration vibration);
static native void vibratorPerformComposedEffect(long controllerPtr,
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
@@ -898,19 +895,11 @@ public class VibratorService extends IVibratorService.Stub
}
}
- private final Runnable mVibrationEndRunnable = new Runnable() {
- @Override
- public void run() {
- onVibrationFinished();
- }
- };
-
@GuardedBy("mLock")
private void doCancelVibrateLocked() {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
try {
- mH.removeCallbacks(mVibrationEndRunnable);
if (mThread != null) {
mThread.cancel();
mThread = null;
@@ -958,13 +947,11 @@ public class VibratorService extends IVibratorService.Stub
private void startVibrationInnerLocked(Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
try {
- long timeout = 0;
mCurrentVibration = vib;
if (vib.effect instanceof VibrationEffect.OneShot) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib);
- timeout = oneShot.getDuration() * ASYNC_TIMEOUT_MULTIPLIER;
} else if (vib.effect instanceof VibrationEffect.Waveform) {
// mThread better be null here. doCancelVibrate should always be
// called before startNextVibrationLocked or startVibrationLocked.
@@ -973,24 +960,13 @@ public class VibratorService extends IVibratorService.Stub
mThread.start();
} else if (vib.effect instanceof VibrationEffect.Prebaked) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- timeout = doVibratorPrebakedEffectLocked(vib);
+ doVibratorPrebakedEffectLocked(vib);
} else if (vib.effect instanceof VibrationEffect.Composed) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
doVibratorComposedEffectLocked(vib);
- // FIXME: We rely on the completion callback here, but I don't think we require that
- // devices which support composition also support the completion callback. If we
- // ever get a device that supports the former but not the latter, then we have no
- // real way of knowing how long a given effect should last.
- timeout = 10_000;
} else {
Slog.e(TAG, "Unknown vibration type, ignoring");
}
- // Post extra runnable to ensure vibration will end even if the HAL or native controller
- // never triggers the callback.
- // TODO: Move ASYNC_TIMEOUT_MULTIPLIER here once native controller is fully integrated.
- if (timeout > 0) {
- mH.postDelayed(mVibrationEndRunnable, timeout);
- }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
@@ -1354,7 +1330,7 @@ public class VibratorService extends IVibratorService.Stub
}
@GuardedBy("mLock")
- private long doVibratorPrebakedEffectLocked(Vibration vib) {
+ private void doVibratorPrebakedEffectLocked(Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
try {
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
@@ -1364,25 +1340,20 @@ public class VibratorService extends IVibratorService.Stub
}
// Input devices don't support prebaked effect, so skip trying it with them.
if (!usingInputDeviceVibrators) {
- long duration = mNativeWrapper.vibratorPerformEffect(prebaked.getId(),
- prebaked.getEffectStrength(), vib,
- hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
- long timeout = duration;
- if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) {
- timeout *= ASYNC_TIMEOUT_MULTIPLIER;
- }
- if (timeout > 0) {
+ long duration = mNativeWrapper.vibratorPerformEffect(
+ prebaked.getId(), prebaked.getEffectStrength(), vib);
+ if (duration > 0) {
noteVibratorOnLocked(vib.uid, duration);
- return timeout;
+ return;
}
}
if (!prebaked.shouldFallback()) {
- return 0;
+ return;
}
VibrationEffect effect = getFallbackEffect(prebaked.getId());
if (effect == null) {
Slog.w(TAG, "Failed to play prebaked effect, no fallback");
- return 0;
+ return;
}
Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
vib.opPkg, vib.reason + " (fallback)");
@@ -1390,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub
linkVibration(fallbackVib);
applyVibrationIntensityScalingLocked(fallbackVib, intensity);
startVibrationInnerLocked(fallbackVib);
- return 0;
+ return;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
@@ -1789,9 +1760,9 @@ public class VibratorService extends IVibratorService.Stub
}
/** Turns vibrator on to perform one of the supported effects. */
- public long vibratorPerformEffect(long effect, long strength, Vibration vibration,
- boolean withCallback) {
- return VibratorService.vibratorPerformEffect(effect, strength, vibration, withCallback);
+ public long vibratorPerformEffect(long effect, long strength, Vibration vibration) {
+ return VibratorService.vibratorPerformEffect(
+ mNativeControllerPtr, effect, strength, vibration);
}
/** Turns vibrator on to perform one of the supported composed effects. */
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3eb26de3a675..b83aa4fb4d86 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -694,12 +694,8 @@ public final class ActiveServices {
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
- callingUid, service, r, allowBackgroundActivityStarts);
- }
-
+ setFgsRestrictionLocked(callingPackage, callingPid,
+ callingUid, service, r, allowBackgroundActivityStarts);
return cmp;
}
@@ -1369,6 +1365,7 @@ public final class ActiveServices {
+ r.shortInstanceName);
}
}
+
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
if (r.fgRequired) {
@@ -1415,6 +1412,24 @@ public final class ActiveServices {
ignoreForeground = true;
}
+ if (!ignoreForeground) {
+ if (!r.mAllowStartForeground) {
+ if (!r.mLoggedInfoAllowStartForeground) {
+ Slog.wtf(TAG, "Background started FGS "
+ + r.mInfoAllowStartForeground);
+ r.mLoggedInfoAllowStartForeground = true;
+ }
+ if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) {
+ Slog.w(TAG,
+ "Service.startForeground() not allowed due to "
+ + " mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ updateServiceForegroundLocked(r.app, true);
+ ignoreForeground = true;
+ }
+ }
+ }
+
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
@@ -2067,12 +2082,7 @@ public final class ActiveServices {
}
}
- if (!s.mAllowWhileInUsePermissionInFgs) {
- s.mAllowWhileInUsePermissionInFgs =
- shouldAllowWhileInUsePermissionInFgsLocked(callingPackage,
- callingPid, callingUid,
- service, s, false);
- }
+ setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, false);
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -4840,21 +4850,48 @@ public final class ActiveServices {
}
/**
- * Should allow while-in-use permissions in foreground service or not.
- * while-in-use permissions in FGS started from background might be restricted.
+ * There are two FGS restrictions:
+ * In R, mAllowWhileInUsePermissionInFgs is to allow while-in-use permissions in foreground
+ * service or not. while-in-use permissions in FGS started from background might be restricted.
+ * In S, mAllowStartForeground is to allow FGS to startForeground or not. Service started
+ * from background may not become a FGS.
* @param callingPackage caller app's package name.
* @param callingUid caller app's uid.
* @param intent intent to start/bind service.
* @param r the service to start.
* @return true if allow, false otherwise.
*/
- private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage,
+ private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
- // Is the background FGS start restriction turned on?
+ // Check DeviceConfig flag.
if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) {
- return true;
+ r.mAllowWhileInUsePermissionInFgs = true;
+ }
+
+ if (!r.mAllowWhileInUsePermissionInFgs || !r.mAllowStartForeground) {
+ final boolean temp = shouldAllowFgsFeatureLocked(callingPackage, callingPid,
+ callingUid, intent, r, allowBackgroundActivityStarts);
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ r.mAllowWhileInUsePermissionInFgs = temp;
+ }
+ if (!r.mAllowStartForeground) {
+ r.mAllowStartForeground = temp;
+ }
}
+ }
+
+ /**
+ * Should allow FGS feature or not.
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param intent intent to start/bind service.
+ * @param r the service to start.
+ * @return true if allow, false otherwise.
+ */
+ private boolean shouldAllowFgsFeatureLocked(String callingPackage,
+ int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ boolean allowBackgroundActivityStarts) {
// Is the allow activity background start flag on?
if (allowBackgroundActivityStarts) {
return true;
@@ -4894,10 +4931,11 @@ public final class ActiveServices {
}
// Is the calling UID at PROCESS_STATE_TOP or above?
- final boolean isCallingUidTopApp = appIsTopLocked(callingUid);
- if (isCallingUidTopApp) {
+ final int uidState = mAm.getUidState(callingUid);
+ if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
return true;
}
+
// Does the calling UID have any visible activity?
final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
if (isCallingUidVisible) {
@@ -4915,6 +4953,19 @@ public final class ActiveServices {
if (isDeviceOwner) {
return true;
}
+
+ final String info =
+ "[callingPackage: " + callingPackage
+ + "; callingUid: " + callingUid
+ + "; uidState: " + ProcessList.makeProcStateString(uidState)
+ + "; intent: " + intent
+ + "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ + "]";
+ if (!info.equals(r.mInfoAllowStartForeground)) {
+ r.mLoggedInfoAllowStartForeground = false;
+ r.mInfoAllowStartForeground = info;
+ }
+
return false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 775119c18037..e9539be8b0d5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -144,6 +144,13 @@ final class ActivityManagerConstants extends ContentObserver {
private static final String KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED =
"default_background_fgs_starts_restriction_enabled";
+ /**
+ * Default value for mFlagFgsStartRestrictionEnabled if not explicitly set in
+ * Settings.Global.
+ */
+ private static final String KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED =
+ "default_fgs_starts_restriction_enabled";
+
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -293,6 +300,11 @@ final class ActivityManagerConstants extends ContentObserver {
// started, the restriction is on while-in-use permissions.)
volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
+ // Indicates whether the foreground service background start restriction is enabled.
+ // When the restriction is enabled, service is not allowed to startForeground from background
+ // at all.
+ volatile boolean mFlagFgsStartRestrictionEnabled = false;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -436,6 +448,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED:
updateBackgroundFgsStartsRestriction();
break;
+ case KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED:
+ updateFgsStartsRestriction();
+ break;
case KEY_OOMADJ_UPDATE_POLICY:
updateOomAdjUpdatePolicy();
break;
@@ -659,6 +674,7 @@ final class ActivityManagerConstants extends ContentObserver {
mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver,
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
}
+
private void updateBackgroundFgsStartsRestriction() {
mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -666,6 +682,13 @@ final class ActivityManagerConstants extends ContentObserver {
/*defaultValue*/ true);
}
+ private void updateFgsStartsRestriction() {
+ mFlagFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_FGS_STARTS_RESTRICTION_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateOomAdjUpdatePolicy() {
OOMADJ_UPDATE_QUICK = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b62ff1c26f8f..a838aadc404e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14470,7 +14470,7 @@ public class ActivityManagerService extends IActivityManager.Stub
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
realCallingPid, userId, false /* allowBackgroundActivityStarts */,
- null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastWhitelist */);
+ null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
@GuardedBy("this")
@@ -15314,7 +15314,7 @@ public class ActivityManagerService extends IActivityManager.Stub
OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken,
- null /*broadcastWhitelist*/);
+ null /* broadcastAllowList */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 4a2703056871..66677b67b6aa 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -146,6 +146,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// the most recent package that start/bind this service.
String mRecentCallingPackage;
+ // allow the service becomes foreground service? Service started from background may not be
+ // allowed to become a foreground service.
+ boolean mAllowStartForeground;
+ String mInfoAllowStartForeground;
+ boolean mLoggedInfoAllowStartForeground;
+
String stringName; // caching of toString
private int lastStartId; // identifier of most recent start request.
@@ -408,6 +414,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
pw.println(mRecentCallingPackage);
+ pw.print(prefix); pw.print("allowStartForeground=");
+ pw.println(mAllowStartForeground);
+ pw.print(prefix); pw.print("infoAllowStartForeground=");
+ pw.println(mInfoAllowStartForeground);
if (delayed) {
pw.print(prefix); pw.print("delayed="); pw.println(delayed);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0658e8139cc2..7420e0a6e828 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1630,7 +1630,7 @@ class UserController implements Handler.Callback {
UserInfo currentUserInfo = getUserInfo(currentUserId);
Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
- mUiHandler.sendMessage(mHandler.obtainMessage(
+ mUiHandler.sendMessage(mUiHandler.obtainMessage(
START_USER_SWITCH_UI_MSG, userNames));
} else {
mHandler.removeMessages(START_USER_SWITCH_FG_MSG);
@@ -2887,13 +2887,18 @@ class UserController implements Handler.Callback {
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
String switchingFromSystemUserMessage, String switchingToSystemUserMessage) {
- if (!mService.mContext.getPackageManager()
+ if (mService.mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
- final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser,
- toUser, true /* above system */, switchingFromSystemUserMessage,
- switchingToSystemUserMessage);
- d.show();
- }
+ // config_customUserSwitchUi is set to true on Automotive as CarSystemUI is
+ // responsible to show the UI; OEMs should not change that, but if they do, we
+ // should at least warn the user...
+ Slog.w(TAG, "Showing user switch dialog on UserController, it could cause a race "
+ + "condition if it's shown by CarSystemUI as well");
+ }
+ final Dialog d = new UserSwitchingDialog(mService, mService.mContext, fromUser,
+ toUser, true /* above system */, switchingFromSystemUserMessage,
+ switchingToSystemUserMessage);
+ d.show();
}
void reportGlobalUsageEventLocked(int event) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b94396634530..23b09294260c 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1282,6 +1282,7 @@ public class AudioService extends IAudioService.Stub
}
if (isPlatformTelevision()) {
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
synchronized (mHdmiClientLock) {
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
updateHdmiCecSinkLocked(mHdmiCecSink | false);
@@ -1301,54 +1302,22 @@ public class AudioService extends IAudioService.Stub
}
}
- /**
- * Update volume states for the given device.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param caller caller of this method
- */
- private void updateVolumeStatesForAudioDevice(int device, String caller) {
+ private void checkAddAllFixedVolumeDevices(int device, String caller) {
final int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- updateVolumeStates(device, streamType, caller);
- }
- }
-
- /**
- * Update volume states for the given device and given stream.
- *
- * This will initialize the volume index if no volume index is available.
- * If the device is the currently routed device, fixed/full volume policies will be applied.
- *
- * @param device a single audio device, ensure that this is not a devices bitmask
- * @param streamType streamType to be updated
- * @param caller caller of this method
- */
- private void updateVolumeStates(int device, int streamType, String caller) {
- if (!mStreamStates[streamType].hasIndexForDevice(device)) {
- // set the default value, if device is affected by a full/fix/abs volume rule, it
- // will taken into account in checkFixedVolumeDevices()
- mStreamStates[streamType].setIndex(
- mStreamStates[mStreamVolumeAlias[streamType]]
- .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
- device, caller, true /*hasModifyAudioSettings*/);
- }
-
- // Check if device to be updated is routed for the given audio stream
- List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributes(
- new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
- for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
- if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
- device)) {
- mStreamStates[streamType].checkFixedVolumeDevices();
+ if (!mStreamStates[streamType].hasIndexForDevice(device)) {
+ // set the default value, if device is affected by a full/fix/abs volume rule, it
+ // will taken into account in checkFixedVolumeDevices()
+ mStreamStates[streamType].setIndex(
+ mStreamStates[mStreamVolumeAlias[streamType]]
+ .getIndex(AudioSystem.DEVICE_OUT_DEFAULT),
+ device, caller, true /*hasModifyAudioSettings*/);
+ }
+ mStreamStates[streamType].checkFixedVolumeDevices();
- // Unmute streams if required if device is full volume
- if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) {
- mStreamStates[streamType].mute(false);
- }
+ // Unmute streams if device is full volume
+ if (mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
}
}
}
@@ -4932,15 +4901,7 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (stream != skipStream) {
- int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
- false /*checkOthers*/);
-
- Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
- for (Integer device : devicesSet) {
- // Update volume states for devices routed for the stream
- updateVolumeStates(device, stream,
- "AudioService#observeDevicesForStreams");
- }
+ mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
}
}
}
@@ -5009,7 +4970,7 @@ public class AudioService extends IAudioService.Stub
+ Integer.toHexString(audioSystemDeviceOut) + " from:" + caller));
// make sure we have a volume entry for this device, and that volume is updated according
// to volume behavior
- updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
+ checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller);
}
/**
@@ -7231,9 +7192,10 @@ public class AudioService extends IAudioService.Stub
// HDMI output
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
}
- updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
- "HdmiPlaybackClient.DisplayStatusCallback");
}
+
+ checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
+ "HdmiPlaybackClient.DisplayStatusCallback");
}
private class MyHdmiControlStatusChangeListenerCallback
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 7bbcdaa2d473..6672daa6f17a 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -949,7 +949,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
if (debug) {
Slog.d(mTag, "Eagerly recreating service for user " + userId);
}
- getServiceForUserLocked(userId);
+ updateCachedServiceLocked(userId);
}
}
onServicePackageRestartedLocked(userId);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index e2f70e320cb8..eb4ab1ceac28 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1937,7 +1937,8 @@ public class MediaSessionService extends SystemService implements Monitor {
// Context#getPackageName() for getting package name that matches with the PID/UID,
// but it doesn't tell which package has created the MediaController, so useless.
return hasMediaControlPermission(controllerPid, controllerUid)
- || hasEnabledNotificationListener(userId, controllerPackageName, uid);
+ || hasEnabledNotificationListener(
+ userId, controllerPackageName, controllerUid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2001,21 +2002,21 @@ public class MediaSessionService extends SystemService implements Monitor {
return resolvedUserId;
}
- private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName,
- int uid) {
- // TODO: revisit this checking code
- // You may not access another user's content as an enabled listener.
- final int userId = UserHandle.getUserHandleForUid(resolvedUserId).getIdentifier();
- if (resolvedUserId != userId) {
+ private boolean hasEnabledNotificationListener(int callingUserId,
+ String controllerPackageName, int controllerUid) {
+ int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
+ if (callingUserId != controllerUserId) {
+ // Enabled notification listener only works within the same user.
return false;
}
- if (mNotificationManager.hasEnabledNotificationListener(packageName,
- UserHandle.getUserHandleForUid(uid))) {
+
+ if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
+ UserHandle.getUserHandleForUid(controllerUid))) {
return true;
}
if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
- + "notification listener");
+ Log.d(TAG, controllerPackageName + " (uid=" + controllerUid
+ + ") doesn't have an enabled notification listener");
}
return false;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a874f612e106..0d1c00dfe035 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2232,7 +2232,7 @@ public class PackageManagerService extends IPackageManager.Stub
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /* broadcastWhitelist */);
+ updateUserIds, instantUserIds, null /* broadcastAllowList */);
}
// if the required verifier is defined, but, is not the installer of record
// for the package, it gets notified
@@ -2242,7 +2242,7 @@ public class PackageManagerService extends IPackageManager.Stub
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /* broadcastWhitelist */);
+ updateUserIds, instantUserIds, null /* broadcastAllowList */);
}
// If package installer is defined, notify package installer about new
// app installed
@@ -2250,7 +2250,7 @@ public class PackageManagerService extends IPackageManager.Stub
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
mRequiredInstallerPackage, null /*finishedReceiver*/,
- firstUserIds, instantUserIds, null /* broadcastWhitelist */);
+ firstUserIds, instantUserIds, null /* broadcastAllowList */);
}
// Send replaced for users that don't see the package for the first time
@@ -2263,19 +2263,19 @@ public class PackageManagerService extends IPackageManager.Stub
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastWhitelist*/);
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/);
}
if (notifyVerifier) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastWhitelist*/);
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/);
}
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds,
- null /*broadcastWhitelist*/);
+ null /*broadcastAllowList*/);
} else if (launchedForRestore && !res.pkg.isSystem()) {
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
@@ -14627,7 +14627,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void sendFirstLaunchBroadcast(String pkgName, String installerPkg,
int[] userIds, int[] instantUserIds) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0,
- installerPkg, null, userIds, instantUserIds, null /* broadcastWhitelist */);
+ installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */);
}
private abstract class HandlerParams {
@@ -18730,14 +18730,14 @@ public class PackageManagerService extends IPackageManager.Stub
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList);
packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
- removedPackage, null, null, null, null /* broadcastWhitelist */);
+ removedPackage, null, null, null, null /* broadcastAllowList */);
if (installerPackageName != null) {
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null, null, null /* broadcastWhitelist */);
+ installerPackageName, null, null, null, null /* broadcastAllowList */);
packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
removedPackage, extras, 0 /*flags*/,
- installerPackageName, null, null, null, null /* broadcastWhitelist */);
+ installerPackageName, null, null, null, null /* broadcastAllowList */);
}
}
@@ -25700,9 +25700,9 @@ interface PackageSender {
* @param instantUserIds User IDs where the action occurred on an instant application
*/
void sendPackageBroadcast(final String action, final String pkg,
- final Bundle extras, final int flags, final String targetPkg,
- final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds,
- @Nullable SparseArray<int[]> broadcastWhitelist);
+ final Bundle extras, final int flags, final String targetPkg,
+ final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds,
+ @Nullable SparseArray<int[]> broadcastAllowList);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
int dataLoaderType);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8b2ba9c98f23..9dda3812fccf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -87,6 +87,7 @@ import android.stats.devicepolicy.DevicePolicyEnums;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -103,7 +104,6 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -4842,9 +4842,17 @@ public class UserManagerService extends IUserManager.Stub {
mUserTypes.valueAt(i).dump(pw, " ");
}
- // Dump package whitelist
- pw.println();
- mSystemPackageInstaller.dump(pw);
+ // TODO: create IndentingPrintWriter at the beginning of dump() and use the proper
+ // indentation methods instead of explicit printing " "
+ try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw)) {
+
+ // Dump SystemPackageInstaller info
+ ipw.println();
+ mSystemPackageInstaller.dump(ipw);
+
+ // NOTE: pw's not available after this point as it's auto-closed by ipw, so new dump
+ // statements should use ipw below
+ }
}
private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 492b84a0a84b..b95404febf72 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -28,15 +28,14 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -723,13 +722,7 @@ class UserSystemPackageInstaller {
return userTypeList;
}
- void dump(PrintWriter pw) {
- try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
- dumpIndented(ipw);
- }
- }
-
- private void dumpIndented(IndentingPrintWriter pw) {
+ void dump(IndentingPrintWriter pw) {
final int mode = getWhitelistMode();
pw.println("Whitelisted packages per user type");
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 03771be0ce7c..63aa80e8269a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,6 +83,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -120,6 +121,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2521,12 +2523,12 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final PermissionsState permissionsState = ps.getPermissionsState();
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+ final int[] userIds = getAllUserIds();
boolean runtimePermissionsRevoked = false;
int[] updatedUserIds = EMPTY_INT_ARRAY;
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
if (permissionsState.isMissing(userId)) {
Collection<String> requestedPermissions;
int targetSdkVersion;
@@ -2592,7 +2594,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
- currentUserIds);
+ userIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -2747,7 +2749,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// a runtime permission being downgraded to an install one.
// Also in permission review mode we keep dangerous permissions
// for legacy apps
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
if (origPermissions.getRuntimePermissionState(
perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
@@ -2770,7 +2772,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -2909,7 +2911,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
- for (int userId : currentUserIds) {
+ for (int userId : userIds) {
// If permission policy is not ready we don't deal with restricted
// permissions as the policy may whitelist some permissions. Once
// the policy is initialized we would re-evaluate permissions.
@@ -3061,10 +3063,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
synchronized (mLock) {
updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
- currentUserIds, updatedUserIds);
+ userIds, updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
- permissionsState, pkg, newImplicitPermissions, currentUserIds, updatedUserIds);
- updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, currentUserIds,
+ permissionsState, pkg, newImplicitPermissions, userIds, updatedUserIds);
+ updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, userIds,
updatedUserIds);
}
@@ -3081,6 +3083,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
/**
+ * Returns all relevant user ids. This list include the current set of created user ids as well
+ * as pre-created user ids.
+ * @return user ids for created users and pre-created users
+ */
+ private int[] getAllUserIds() {
+ final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ t.traceBegin("getAllUserIds");
+ List<UserInfo> users = UserManagerService.getInstance().getUsers(
+ /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
+ int size = users.size();
+ final int[] userIds = new int[size];
+ for (int i = 0; i < size; i++) {
+ userIds[i] = users.get(i).id;
+ }
+ t.traceEnd();
+ return userIds;
+ }
+
+ /**
* Revoke permissions that are not implicit anymore and that have
* {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
*
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 2a74b3d23829..5aedfc19028b 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -28,8 +28,6 @@ import static android.os.Process.SYSTEM_UID;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.app.AppOpsManager;
-import android.app.role.OnRoleHoldersChangedListener;
-import android.app.role.RoleManager;
import android.app.slice.ISliceManager;
import android.app.slice.SliceSpec;
import android.app.usage.UsageStatsManagerInternal;
@@ -41,9 +39,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
@@ -65,7 +61,6 @@ import com.android.internal.app.AssistUtils;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -77,10 +72,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Supplier;
public class SliceManagerService extends ISliceManager.Stub {
@@ -88,16 +80,13 @@ public class SliceManagerService extends ISliceManager.Stub {
private final Object mLock = new Object();
private final Context mContext;
- private final PackageManagerInternal mPackageManagerInternal;
private final AppOpsManager mAppOps;
private final AssistUtils mAssistUtils;
@GuardedBy("mLock")
private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
@GuardedBy("mLock")
- private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
- @GuardedBy("mLock")
- private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
+ private final SparseArray<String> mLastAssistantPackage = new SparseArray<>();
private final Handler mHandler;
private final SlicePermissionManager mPermissions;
@@ -110,8 +99,6 @@ public class SliceManagerService extends ISliceManager.Stub {
@VisibleForTesting
SliceManagerService(Context context, Looper looper) {
mContext = context;
- mPackageManagerInternal = Objects.requireNonNull(
- LocalServices.getService(PackageManagerInternal.class));
mAppOps = context.getSystemService(AppOpsManager.class);
mAssistUtils = new AssistUtils(context);
mHandler = new Handler(looper);
@@ -124,7 +111,6 @@ public class SliceManagerService extends ISliceManager.Stub {
filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- mRoleObserver = new RoleObserver();
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
}
@@ -174,8 +160,7 @@ public class SliceManagerService extends ISliceManager.Stub {
mHandler.post(() -> {
if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
mAppUsageStats.reportEvent(slicePkg, user,
- isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
- ? SLICE_PINNED_PRIV : SLICE_PINNED);
+ isAssistant(pkg, user) ? SLICE_PINNED_PRIV : SLICE_PINNED);
}
});
}
@@ -440,38 +425,19 @@ public class SliceManagerService extends ISliceManager.Stub {
private boolean hasFullSliceAccess(String pkg, int userId) {
long ident = Binder.clearCallingIdentity();
try {
- boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
- || isGrantedFullAccess(pkg, userId);
- return ret;
+ return isAssistant(pkg, userId) || isGrantedFullAccess(pkg, userId);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private boolean isAssistant(String pkg, int userId) {
- return getAssistantMatcher(userId).matches(pkg);
- }
-
- private boolean isDefaultHomeApp(String pkg, int userId) {
- return getHomeMatcher(userId).matches(pkg);
- }
-
- private PackageMatchingCache getAssistantMatcher(int userId) {
- PackageMatchingCache matcher = mAssistantLookup.get(userId);
- if (matcher == null) {
- matcher = new PackageMatchingCache(() -> getAssistant(userId));
- mAssistantLookup.put(userId, matcher);
- }
- return matcher;
- }
-
- private PackageMatchingCache getHomeMatcher(int userId) {
- PackageMatchingCache matcher = mHomeLookup.get(userId);
- if (matcher == null) {
- matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
- mHomeLookup.put(userId, matcher);
+ if (pkg == null) return false;
+ if (!pkg.equals(mLastAssistantPackage.get(userId))) {
+ // Failed on cached value, try updating.
+ mLastAssistantPackage.put(userId, getAssistant(userId));
}
- return matcher;
+ return pkg.equals(mLastAssistantPackage.get(userId));
}
private String getAssistant(int userId) {
@@ -482,111 +448,6 @@ public class SliceManagerService extends ISliceManager.Stub {
return cn.getPackageName();
}
- /**
- * A cached value of the default home app
- */
- private String mCachedDefaultHome = null;
-
- // Based on getDefaultHome in ShortcutService.
- // TODO: Unify if possible
- @VisibleForTesting
- protected String getDefaultHome(int userId) {
-
- // Set VERIFY to true to run the cache in "shadow" mode for cache
- // testing. Do not commit set to true;
- final boolean VERIFY = false;
-
- if (mCachedDefaultHome != null) {
- if (!VERIFY) {
- return mCachedDefaultHome;
- }
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
-
- // Default launcher from package manager.
- final ComponentName defaultLauncher = mPackageManagerInternal
- .getHomeActivitiesAsUser(allHomeCandidates, userId);
-
- ComponentName detected = defaultLauncher;
-
- // Cache the default launcher. It is not a problem if the
- // launcher is null - eventually, the default launcher will be
- // set to something non-null.
- mCachedDefaultHome = ((detected != null) ? detected.getPackageName() : null);
-
- if (detected == null) {
- // If we reach here, that means it's the first check since the user was created,
- // and there's already multiple launchers and there's no default set.
- // Find the system one with the highest priority.
- // (We need to check the priority too because of FallbackHome in Settings.)
- // If there's no system launcher yet, then no one can access slices, until
- // the user explicitly sets one.
- final int size = allHomeCandidates.size();
-
- int lastPriority = Integer.MIN_VALUE;
- for (int i = 0; i < size; i++) {
- final ResolveInfo ri = allHomeCandidates.get(i);
- if (!ri.activityInfo.applicationInfo.isSystemApp()) {
- continue;
- }
- if (ri.priority < lastPriority) {
- continue;
- }
- detected = ri.activityInfo.getComponentName();
- lastPriority = ri.priority;
- }
- }
- final String ret = ((detected != null) ? detected.getPackageName() : null);
- if (VERIFY) {
- if (mCachedDefaultHome != null && !mCachedDefaultHome.equals(ret)) {
- Slog.e(TAG, "getDefaultHome() cache failure, is " +
- mCachedDefaultHome + " should be " + ret);
- }
- }
- return ret;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- public void invalidateCachedDefaultHome() {
- mCachedDefaultHome = null;
- }
-
- /**
- * Listen for changes in the roles, and invalidate the cached default
- * home as necessary.
- */
- private RoleObserver mRoleObserver;
-
- class RoleObserver implements OnRoleHoldersChangedListener {
- private RoleManager mRm;
- private final Executor mExecutor;
-
- RoleObserver() {
- mExecutor = mContext.getMainExecutor();
- register();
- }
-
- public void register() {
- mRm = mContext.getSystemService(RoleManager.class);
- if (mRm != null) {
- mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
- invalidateCachedDefaultHome();
- }
- }
-
- @Override
- public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
- if (RoleManager.ROLE_HOME.equals(roleName)) {
- invalidateCachedDefaultHome();
- }
- }
- }
-
private boolean isGrantedFullAccess(String pkg, int userId) {
return mPermissions.hasFullAccess(pkg, userId);
}
@@ -635,30 +496,6 @@ public class SliceManagerService extends ISliceManager.Stub {
return mPermissions.getAllPackagesGranted(pkg);
}
- /**
- * Holder that caches a package that has access to a slice.
- */
- static class PackageMatchingCache {
-
- private final Supplier<String> mPkgSource;
- private String mCurrentPkg;
-
- public PackageMatchingCache(Supplier<String> pkgSource) {
- mPkgSource = pkgSource;
- }
-
- public boolean matches(String pkgCandidate) {
- if (pkgCandidate == null) return false;
-
- if (Objects.equals(pkgCandidate, mCurrentPkg)) {
- return true;
- }
- // Failed on cached value, try updating.
- mCurrentPkg = mPkgSource.get();
- return Objects.equals(pkgCandidate, mCurrentPkg);
- }
- }
-
public static class Lifecycle extends SystemService {
private SliceManagerService mService;
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index c2b0d1067e38..0ca36e0fc258 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -72,6 +72,10 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED);
}
+ // TODO(b/149014708) Replace this with real logic when the settings storage is fully
+ // implemented.
+ builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);
+
// The ability to make manual time zone suggestions can also be restricted by policy. With
// the current logic above, this could lead to a situation where a device hardware does not
// support auto detection, the device has been forced into "auto" mode by an admin and the
@@ -90,6 +94,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
return new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(isAutoDetectionEnabled())
+ .setGeoDetectionEnabled(isGeoDetectionEnabled())
.build();
}
@@ -105,8 +110,11 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
// detection: if we wrote it down then we'd set the default explicitly. That might influence
// what happens on later releases that do support auto detection on the same hardware.
if (isAutoDetectionSupported()) {
- final int value = configuration.isAutoDetectionEnabled() ? 1 : 0;
- Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, value);
+ final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0;
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue);
+
+ final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled();
+ // TODO(b/149014708) Write this down to user-scoped settings once implemented.
}
}
@@ -126,6 +134,14 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
}
@Override
+ public boolean isGeoDetectionEnabled() {
+ // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's
+ // location toggle will act as an override for this setting, i.e. so that the setting will
+ // return false if the location toggle is disabled.
+ return false;
+ }
+
+ @Override
public boolean isDeviceTimeZoneInitialized() {
// timezone.equals("GMT") will be true and only true if the time zone was
// set to a default value by the system server (when starting, system server
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index 3d9ec6475a8b..fb7a73d12632 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
* The internal (in-process) system server API for the {@link
* com.android.server.timezonedetector.TimeZoneDetectorService}.
*
+ * <p>The methods on this class can be called from any thread.
* @hide
*/
public interface TimeZoneDetectorInternal extends Dumpable.Container {
@@ -29,7 +30,7 @@ public interface TimeZoneDetectorInternal extends Dumpable.Container {
/**
* Suggests the current time zone, determined using geolocation, to the detector. The
* detector may ignore the signal based on system settings, whether better information is
- * available, and so on.
+ * available, and so on. This method may be implemented asynchronously.
*/
void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 4464f7d136e3..15412a0d14a1 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -58,6 +58,7 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion) {
Objects.requireNonNull(timeZoneSuggestion);
+ // All strategy calls must take place on the mHandler thread.
mHandler.post(
() -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion));
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 7467439905eb..d81f949742bd 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -130,6 +130,10 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
service.handleAutoTimeZoneConfigChanged();
}
});
+ // TODO(b/149014708) Listen for changes to geolocation time zone detection enabled config.
+ // This should also include listening to the current user and the current user's location
+ // toggle since the config is user-scoped and the location toggle overrides the geolocation
+ // time zone enabled setting.
return service;
}
@@ -280,7 +284,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
void handleConfigurationChanged() {
// Note: we could trigger an async time zone detection operation here via a call to
- // handleAutoTimeZoneDetectionChanged(), but that is triggered in response to the underlying
+ // handleAutoTimeZoneConfigChanged(), but that is triggered in response to the underlying
// setting value changing so it is currently unnecessary. If we get to a point where all
// configuration changes are guaranteed to happen in response to an updateConfiguration()
// call, then we can remove that path and call it here instead.
@@ -288,7 +292,6 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
// Configuration has changed, but each user may have a different view of the configuration.
// It's possible that this will cause unnecessary notifications but that shouldn't be a
// problem.
-
synchronized (mConfigurationListeners) {
final int userCount = mConfigurationListeners.size();
for (int userIndex = 0; userIndex < userCount; userIndex++) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index f947a6554412..c5b7e39f4fef 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -30,9 +30,9 @@ import android.util.IndentingPrintWriter;
* <p>The strategy uses suggestions to decide whether to modify the device's time zone setting
* and what to set it to.
*
- * <p>Most calls will be handled by a single thread but that is not true for all calls. For example
- * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread so
- * implementations mustvhandle thread safety.
+ * <p>Most calls will be handled by a single thread, but that is not true for all calls. For example
+ * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread concurrently
+ * with other operations so implementations must still handle thread safety.
*
* @hide
*/
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 9c36c3921e3e..d1369a289428 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -23,6 +23,7 @@ import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_S
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.timezonedetector.TimeZoneCapabilities.CAPABILITY_POSSESSED;
import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneConfiguration.PROPERTY_GEO_DETECTION_ENABLED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -98,6 +99,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
boolean isAutoDetectionEnabled();
/**
+ * Returns whether geolocation can be used for time zone detection when {@link
+ * #isAutoDetectionEnabled()} returns {@code true}.
+ */
+ boolean isGeoDetectionEnabled();
+
+ /**
* Returns true if the device has had an explicit time zone set.
*/
boolean isDeviceTimeZoneInitialized();
@@ -200,7 +207,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
*/
@GuardedBy("this")
private ArrayMapWithHistory<Integer, QualifiedTelephonyTimeZoneSuggestion>
- mSuggestionBySlotIndex = new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+ mTelephonySuggestionsBySlotIndex =
+ new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+
+ /**
+ * The latest geolocation suggestion received.
+ */
+ @GuardedBy("this")
+ private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
+ new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
@GuardedBy("this")
private final List<Dumpable> mDumpables = new ArrayList<>();
@@ -284,17 +299,26 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
private static boolean containsAutoTimeDetectionProperties(
@NonNull TimeZoneConfiguration configuration) {
- return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED);
+ return configuration.hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
+ || configuration.hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
}
@Override
public synchronized void suggestGeolocationTimeZone(
@NonNull GeolocationTimeZoneSuggestion suggestion) {
+ if (DBG) {
+ Slog.d(LOG_TAG, "Geolocation suggestion received. newSuggestion=" + suggestion);
+ }
+
Objects.requireNonNull(suggestion);
+ mLatestGeoLocationSuggestion.set(suggestion);
- // TODO Implement this.
- throw new UnsupportedOperationException(
- "Geo-location time zone detection is not currently implemented");
+ // Now perform auto time zone detection. The new suggestion may be used to modify the time
+ // zone setting.
+ if (mCallback.isGeoDetectionEnabled()) {
+ String reason = "New geolocation time zone suggested. suggestion=" + suggestion;
+ doAutoTimeZoneDetection(reason);
+ }
}
@Override
@@ -332,12 +356,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
new QualifiedTelephonyTimeZoneSuggestion(suggestion, score);
// Store the suggestion against the correct slotIndex.
- mSuggestionBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion);
+ mTelephonySuggestionsBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion);
// Now perform auto time zone detection. The new suggestion may be used to modify the time
// zone setting.
- String reason = "New telephony time suggested. suggestion=" + suggestion;
- doAutoTimeZoneDetection(reason);
+ if (!mCallback.isGeoDetectionEnabled()) {
+ String reason = "New telephony time zone suggested. suggestion=" + suggestion;
+ doAutoTimeZoneDetection(reason);
+ }
}
private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) {
@@ -363,9 +389,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
}
/**
- * Finds the best available time zone suggestion from all slotIndexes. If it is high-enough
- * quality and automatic time zone detection is enabled then it will be set on the device. The
- * outcome can be that this strategy becomes / remains un-opinionated and nothing is set.
+ * Performs automatic time zone detection.
*/
@GuardedBy("this")
private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
@@ -374,6 +398,62 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
return;
}
+ // Use the right suggestions based on the current configuration. This check is potentially
+ // race-prone until this value is set via a call to TimeZoneDetectorStrategy.
+ if (mCallback.isGeoDetectionEnabled()) {
+ doGeolocationTimeZoneDetection(detectionReason);
+ } else {
+ doTelephonyTimeZoneDetection(detectionReason);
+ }
+ }
+
+ /**
+ * Detects the time zone using the latest available geolocation time zone suggestion, if one is
+ * available. The outcome can be that this strategy becomes / remains un-opinionated and nothing
+ * is set.
+ */
+ @GuardedBy("this")
+ private void doGeolocationTimeZoneDetection(@NonNull String detectionReason) {
+ GeolocationTimeZoneSuggestion latestGeolocationSuggestion =
+ mLatestGeoLocationSuggestion.get();
+ if (latestGeolocationSuggestion == null) {
+ return;
+ }
+
+ List<String> zoneIds = latestGeolocationSuggestion.getZoneIds();
+ if (zoneIds == null || zoneIds.isEmpty()) {
+ // This means the client has become uncertain about the time zone or it is certain there
+ // is no known zone. In either case we must leave the existing time zone setting as it
+ // is.
+ return;
+ }
+
+ // GeolocationTimeZoneSuggestion has no measure of quality. We assume all suggestions are
+ // reliable.
+ String zoneId;
+
+ // Introduce bias towards the device's current zone when there are multiple zone suggested.
+ String deviceTimeZone = mCallback.getDeviceTimeZone();
+ if (zoneIds.contains(deviceTimeZone)) {
+ if (DBG) {
+ Slog.d(LOG_TAG,
+ "Geo tz suggestion contains current device time zone. Applying bias.");
+ }
+ zoneId = deviceTimeZone;
+ } else {
+ zoneId = zoneIds.get(0);
+ }
+ setDeviceTimeZoneIfRequired(zoneId, detectionReason);
+ }
+
+ /**
+ * Detects the time zone using the latest available telephony time zone suggestions.
+ * Finds the best available time zone suggestion from all slotIndexes. If it is high-enough
+ * quality and automatic time zone detection is enabled then it will be set on the device. The
+ * outcome can be that this strategy becomes / remains un-opinionated and nothing is set.
+ */
+ @GuardedBy("this")
+ private void doTelephonyTimeZoneDetection(@NonNull String detectionReason) {
QualifiedTelephonyTimeZoneSuggestion bestTelephonySuggestion =
findBestTelephonySuggestion();
@@ -468,9 +548,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
// slotIndex and find the best. Note that we deliberately do not look at age: the caller can
// rate-limit so age is not a strong indicator of confidence. Instead, the callers are
// expected to withdraw suggestions they no longer have confidence in.
- for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) {
+ for (int i = 0; i < mTelephonySuggestionsBySlotIndex.size(); i++) {
QualifiedTelephonyTimeZoneSuggestion candidateSuggestion =
- mSuggestionBySlotIndex.valueAt(i);
+ mTelephonySuggestionsBySlotIndex.valueAt(i);
if (candidateSuggestion == null) {
// Unexpected
continue;
@@ -505,14 +585,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@Override
public synchronized void handleAutoTimeZoneConfigChanged() {
if (DBG) {
- Slog.d(LOG_TAG, "handleTimeZoneDetectionChange() called");
- }
- if (mCallback.isAutoDetectionEnabled()) {
- // When the user enabled time zone detection, run the time zone detection and change the
- // device time zone if possible.
- String reason = "Auto time zone detection setting enabled.";
- doAutoTimeZoneDetection(reason);
+ Slog.d(LOG_TAG, "handleAutoTimeZoneConfigChanged()");
}
+
+ doAutoTimeZoneDetection("handleAutoTimeZoneConfigChanged()");
}
@Override
@@ -532,15 +608,21 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
ipw.println("mCallback.isDeviceTimeZoneInitialized()="
+ mCallback.isDeviceTimeZoneInitialized());
ipw.println("mCallback.getDeviceTimeZone()=" + mCallback.getDeviceTimeZone());
+ ipw.println("mCallback.isGeoDetectionEnabled()=" + mCallback.isGeoDetectionEnabled());
ipw.println("Time zone change log:");
ipw.increaseIndent(); // level 2
mTimeZoneChangesLog.dump(ipw);
ipw.decreaseIndent(); // level 2
+ ipw.println("Geolocation suggestion history:");
+ ipw.increaseIndent(); // level 2
+ mLatestGeoLocationSuggestion.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
ipw.println("Telephony suggestion history:");
ipw.increaseIndent(); // level 2
- mSuggestionBySlotIndex.dump(ipw);
+ mTelephonySuggestionsBySlotIndex.dump(ipw);
ipw.decreaseIndent(); // level 2
ipw.decreaseIndent(); // level 1
@@ -555,7 +637,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@VisibleForTesting
public synchronized QualifiedTelephonyTimeZoneSuggestion getLatestTelephonySuggestion(
int slotIndex) {
- return mSuggestionBySlotIndex.get(slotIndex);
+ return mTelephonySuggestionsBySlotIndex.get(slotIndex);
+ }
+
+ /**
+ * A method used to inspect strategy state during tests. Not intended for general use.
+ */
+ @VisibleForTesting
+ public GeolocationTimeZoneSuggestion getLatestGeolocationSuggestion() {
+ return mLatestGeoLocationSuggestion.get();
}
/**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 2f695c6fd3f1..202a3dcf46dc 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3070,7 +3070,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
mLockWallpaperMap.put(userId, wallpaper);
ensureSaneWallpaperData(wallpaper);
} else {
- // sanity fallback: we're in bad shape, but establishing a known
+ // rationality fallback: we're in bad shape, but establishing a known
// valid system+lock WallpaperData will keep us from dying.
Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index b6633ced771b..529fb8838aa1 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -17,9 +17,7 @@
#define LOG_TAG "VibratorService"
#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
@@ -28,19 +26,11 @@
#include <utils/misc.h>
#include <utils/Log.h>
-#include <hardware/vibrator.h>
#include <inttypes.h>
-#include <stdio.h>
#include <vibratorservice/VibratorHalController.h>
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::vibrator::V1_0::EffectStrength;
-using android::hardware::vibrator::V1_0::Status;
-using android::hardware::vibrator::V1_1::Effect_1_1;
-
namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;
@@ -87,150 +77,7 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-class VibratorCallback {
- public:
- VibratorCallback(JNIEnv *env, jobject vibration) :
- mVibration(MakeGlobalRefOrDie(env, vibration)) {}
-
- ~VibratorCallback() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->DeleteGlobalRef(mVibration);
- }
-
- void onComplete() {
- auto env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(mVibration, sMethodIdOnComplete);
- }
-
- private:
- jobject mVibration;
-};
-
-class AidlVibratorCallback : public aidl::BnVibratorCallback {
- public:
- AidlVibratorCallback(JNIEnv *env, jobject vibration) :
- mCb(env, vibration) {}
-
- binder::Status onComplete() override {
- mCb.onComplete();
- return binder::Status::ok(); // oneway, local call
- }
-
- private:
- VibratorCallback mCb;
-};
-
-static constexpr int NUM_TRIES = 2;
-
-template<class R>
-inline R NoneStatus() {
- using ::android::hardware::Status;
- return Status::fromExceptionCode(Status::EX_NONE);
-}
-
-template<>
-inline binder::Status NoneStatus() {
- using binder::Status;
- return Status::fromExceptionCode(Status::EX_NONE);
-}
-
-// Creates a Return<R> with STATUS::EX_NULL_POINTER.
-template<class R>
-inline R NullptrStatus() {
- using ::android::hardware::Status;
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-}
-
-template<>
-inline binder::Status NullptrStatus() {
- using binder::Status;
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-}
-
-template <typename I>
-sp<I> getService() {
- return I::getService();
-}
-
-template <>
-sp<aidl::IVibrator> getService() {
- return waitForVintfService<aidl::IVibrator>();
-}
-
-template <typename I>
-sp<I> tryGetService() {
- return I::tryGetService();
-}
-
-template <>
-sp<aidl::IVibrator> tryGetService() {
- return checkVintfService<aidl::IVibrator>();
-}
-
-template <typename I>
-class HalWrapper {
- public:
- static std::unique_ptr<HalWrapper> Create() {
- // Assume that if getService returns a nullptr, HAL is not available on the
- // device.
- auto hal = getService<I>();
- return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
- }
-
- // Helper used to transparently deal with the vibrator HAL becoming unavailable.
- template<class R, class... Args0, class... Args1>
- R call(R (I::* fn)(Args0...), Args1&&... args1) {
- // Return<R> doesn't have a default constructor, so make a Return<R> with
- // STATUS::EX_NONE.
- R ret{NoneStatus<R>()};
-
- // Note that ret is guaranteed to be changed after this loop.
- for (int i = 0; i < NUM_TRIES; ++i) {
- ret = (mHal == nullptr) ? NullptrStatus<R>()
- : (*mHal.*fn)(std::forward<Args1>(args1)...);
-
- if (ret.isOk()) {
- break;
- }
-
- ALOGE("Failed to issue command to vibrator HAL. Retrying.");
-
- // Restoring connection to the HAL.
- mHal = tryGetService<I>();
- }
- return ret;
- }
-
- private:
- HalWrapper(sp<I> &&hal) : mHal(std::move(hal)) {}
-
- private:
- sp<I> mHal;
-};
-
-template <typename I>
-static auto getHal() {
- static auto sHalWrapper = HalWrapper<I>::Create();
- return sHalWrapper.get();
-}
-
-template<class R, class I, class... Args0, class... Args1>
-R halCall(R (I::* fn)(Args0...), Args1&&... args1) {
- auto hal = getHal<I>();
- return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
-}
-
-template<class R>
-bool isValidEffect(jlong effect) {
- if (effect < 0) {
- return false;
- }
- R val = static_cast<R>(effect);
- auto iter = hardware::hidl_enum_range<R>();
- return val >= *iter.begin() && val <= *std::prev(iter.end());
-}
-
-static void callVibrationOnComplete(jobject vibration) {
+static inline void callVibrationOnComplete(jobject vibration) {
if (vibration == nullptr) {
return;
}
@@ -257,14 +104,6 @@ static void destroyVibratorController(void* rawVibratorController) {
}
static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- // IBinder::pingBinder isn't accessible as a pointer function
- // but getCapabilities can serve the same purpose
- int32_t cap;
- hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
- } else {
- halCall(&V1_0::IVibrator::ping).isOk();
- }
std::unique_ptr<vibrator::HalController> controller =
std::make_unique<vibrator::HalController>();
controller->init();
@@ -342,70 +181,19 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl
return effects;
}
-static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect, jlong strength,
- jobject vibration, jboolean withCallback) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t lengthMs;
- sp<AidlVibratorCallback> effectCallback =
- (withCallback != JNI_FALSE ? new AidlVibratorCallback(env, vibration) : nullptr);
- aidl::Effect effectType(static_cast<aidl::Effect>(effect));
- aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
-
- auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
- if (!status.isOk()) {
- if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) {
- ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
- ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string());
- }
- return -1;
- }
- return lengthMs;
- } else {
- Status status;
- uint32_t lengthMs;
- auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
- EffectStrength effectStrength(static_cast<EffectStrength>(strength));
-
- Return<void> ret;
- if (isValidEffect<V1_0::Effect>(effect)) {
- ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
- effectStrength, callback);
- } else if (isValidEffect<Effect_1_1>(effect)) {
- ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
- effectStrength, callback);
- } else if (isValidEffect<V1_2::Effect>(effect)) {
- ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
- effectStrength, callback);
- } else if (isValidEffect<V1_3::Effect>(effect)) {
- ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
- effectStrength, callback);
- } else {
- ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
- static_cast<int32_t>(effect));
- return -1;
- }
-
- if (!ret.isOk()) {
- ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
- return -1;
- }
-
- if (status == Status::OK) {
- return lengthMs;
- } else if (status != Status::UNSUPPORTED_OPERATION) {
- // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
- // doesn't have a pre-defined waveform to perform for it, so we should just give the
- // opportunity to fall back to the framework waveforms.
- ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
- ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
- static_cast<int32_t>(strength), static_cast<uint32_t>(status));
- }
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jlong effect, jlong strength, jobject vibration) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorPerformEffect failed because controller was not initialized");
+ return -1;
}
-
- return -1;
+ aidl::Effect effectType = static_cast<aidl::Effect>(effect);
+ aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
+ jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
+ auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
+ auto result = controller->performEffect(effectType, effectStrength, callback);
+ return result.isOk() ? result.value().count() : -1;
}
static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
@@ -464,7 +252,7 @@ static const JNINativeMethod method_table[] = {
{"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn},
{"vibratorOff", "(J)V", (void*)vibratorOff},
{"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
- {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J",
+ {"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J",
(void*)vibratorPerformEffect},
{"vibratorPerformComposedEffect",
"(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java
index 27a116c8043e..1586a33ba0e9 100644
--- a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java
+++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java
@@ -34,7 +34,8 @@ public final class SystemCaptionsManagerService extends
context,
com.android.internal.R.string.config_defaultSystemCaptionsManagerService),
/*disallowProperty=*/ null,
- /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+ /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER
+ | PACKAGE_RESTART_POLICY_REFRESH_EAGER);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 7d6d90c4578c..02d10e3b6ce1 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@@ -310,7 +309,7 @@ public class VibratorServiceTest {
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_CLICK),
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
- any(VibratorService.Vibration.class), eq(false));
+ any(VibratorService.Vibration.class));
}
@Test
@@ -387,21 +386,26 @@ public class VibratorServiceTest {
}
@Test
- public void vibrate_withOneShotAndNativeCallbackNotTriggered_finishesVibrationViaFallback() {
+ public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
+ when(mNativeWrapperMock.vibratorGetSupportedEffects())
+ .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ doAnswer(invocation -> {
+ ((VibratorService.Vibration) invocation.getArgument(2)).onComplete();
+ return 10_000L; // 10s
+ }).when(mNativeWrapperMock).vibratorPerformEffect(
+ anyLong(), anyLong(), any(VibratorService.Vibration.class));
VibratorService service = createService();
Mockito.clearInvocations(mNativeWrapperMock);
- vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
-
- verify(mNativeWrapperMock).vibratorOff();
- verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
- Mockito.clearInvocations(mNativeWrapperMock);
-
- // Run the scheduled callback to finish one-shot vibration.
- mTestLooper.moveTimeForward(200);
- mTestLooper.dispatchAll();
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
- verify(mNativeWrapperMock).vibratorOff();
+ InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
+ any(VibratorService.Vibration.class));
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@Test
@@ -447,30 +451,6 @@ public class VibratorServiceTest {
}
@Test
- public void vibrate_withComposedAndNativeCallbackNotTriggered_finishesVibrationViaFallback() {
- mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
- VibratorService service = createService();
- Mockito.clearInvocations(mNativeWrapperMock);
-
- VibrationEffect effect = VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
- .compose();
- vibrate(service, effect);
-
- verify(mNativeWrapperMock).vibratorOff();
- verify(mNativeWrapperMock).vibratorPerformComposedEffect(
- any(VibrationEffect.Composition.PrimitiveEffect[].class),
- any(VibratorService.Vibration.class));
- Mockito.clearInvocations(mNativeWrapperMock);
-
- // Run the scheduled callback to finish one-shot vibration.
- mTestLooper.moveTimeForward(10000); // 10s
- mTestLooper.dispatchAll();
-
- verify(mNativeWrapperMock).vibratorOff();
- }
-
- @Test
public void vibrate_whenBinderDies_cancelsVibration() {
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
doAnswer(invocation -> {
@@ -574,15 +554,15 @@ public class VibratorServiceTest {
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_CLICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any(), anyBoolean());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any());
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_TICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any(), anyBoolean());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any());
verify(mNativeWrapperMock).vibratorPerformEffect(
eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
- eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any(), anyBoolean());
+ eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any());
verify(mNativeWrapperMock, never()).vibratorPerformEffect(
- eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any(), anyBoolean());
+ eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 80f145b16147..35d6f470a504 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -48,7 +48,7 @@ public class PackageManagerServiceTest {
public void sendPackageBroadcast(final String action, final String pkg,
final Bundle extras, final int flags, final String targetPkg,
final IIntentReceiver finishedReceiver, final int[] userIds,
- int[] instantUserIds, SparseArray<int[]> broadcastWhitelist) {
+ int[] instantUserIds, SparseArray<int[]> broadcastAllowList) {
}
public void sendPackageAddedForNewUsers(String packageName,
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index 9f9ec31f0c91..f96ebda67602 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -23,6 +23,8 @@ import com.google.common.truth.Expect
import org.junit.Rule
import org.junit.Test
+import org.junit.rules.Timeout
+import java.util.concurrent.TimeUnit
/**
* Collects APKs from the device and verifies that the new parsing behavior outputs
@@ -32,6 +34,9 @@ import org.junit.Test
class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
@get:Rule
+ val timeout = Timeout(4, TimeUnit.MINUTES)
+
+ @get:Rule
val expect = Expect.create()
@Test
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index dcf319058ca2..e5e931115c05 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -27,6 +27,9 @@ import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.util.IndentingPrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
private StrategyListener mListener;
@@ -41,6 +44,7 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
private boolean mHandleAutoTimeZoneConfigChangedCalled;
private boolean mDumpCalled;
+ private final List<Dumpable> mDumpables = new ArrayList<>();
@Override
public void setStrategyListener(@NonNull StrategyListener listener) {
@@ -105,7 +109,7 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
@Override
public void addDumpable(Dumpable dumpable) {
- // Stubbed
+ mDumpables.add(dumpable);
}
@Override
@@ -149,4 +153,8 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
+
+ void verifyHasDumpable(Dumpable expected) {
+ assertTrue(mDumpables.contains(expected));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index 0e2c22756097..e9d57e52ce69 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -75,6 +75,16 @@ public class TimeZoneDetectorInternalImplTest {
mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
}
+ @Test
+ public void testAddDumpable() throws Exception {
+ Dumpable stubbedDumpable = mock(Dumpable.class);
+
+ mTimeZoneDetectorInternal.addDumpable(stubbedDumpable);
+ mTestHandler.assertTotalMessagesEnqueued(0);
+
+ mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable);
+ }
+
private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
return new GeolocationTimeZoneSuggestion(ARBITRARY_ZONE_IDS);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 8034cacc6923..3a1ec4f90d7a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -52,6 +52,7 @@ import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
public class TimeZoneDetectorServiceTest {
@@ -253,6 +254,39 @@ public class TimeZoneDetectorServiceTest {
}
@Test(expected = SecurityException.class)
+ public void testSuggestGeolocationTimeZone_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+ GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
+
+ try {
+ mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion);
+ fail();
+ } finally {
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME_ZONE),
+ anyString());
+ }
+ }
+
+ @Test
+ public void testSuggestGeolocationTimeZone() throws Exception {
+ doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+
+ GeolocationTimeZoneSuggestion timeZoneSuggestion = createGeolocationTimeZoneSuggestion();
+
+ mTimeZoneDetectorService.suggestGeolocationTimeZone(timeZoneSuggestion);
+ mTestHandler.assertTotalMessagesEnqueued(1);
+
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME_ZONE),
+ anyString());
+
+ mTestHandler.waitForMessagesToBeProcessed();
+ mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
+ }
+
+ @Test(expected = SecurityException.class)
public void testSuggestManualTimeZone_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
@@ -346,7 +380,7 @@ public class TimeZoneDetectorServiceTest {
}
@Test
- public void testAutoTimeZoneDetectionChanged() throws Exception {
+ public void testHandleAutoTimeZoneConfigChanged() throws Exception {
mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
@@ -370,10 +404,15 @@ public class TimeZoneDetectorServiceTest {
private static TimeZoneCapabilities createTimeZoneCapabilities() {
return new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED)
.build();
}
+ private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
+ return new GeolocationTimeZoneSuggestion(Arrays.asList("TestZoneId"));
+ }
+
private static ManualTimeZoneSuggestion createManualTimeZoneSuggestion() {
return new ManualTimeZoneSuggestion("TestZoneId");
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 68554451e43a..a6caa4299ef6 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -41,6 +41,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
@@ -56,10 +57,10 @@ import org.junit.Before;
import org.junit.Test;
import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -93,16 +94,26 @@ public class TimeZoneDetectorStrategyImplTest {
TELEPHONY_SCORE_HIGHEST),
};
- private static final TimeZoneConfiguration CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED =
+ private static final TimeZoneConfiguration CONFIG_AUTO_ENABLED =
new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(true)
.build();
- private static final TimeZoneConfiguration CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED =
+ private static final TimeZoneConfiguration CONFIG_AUTO_DISABLED =
new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(false)
.build();
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_DISABLED =
+ new TimeZoneConfiguration.Builder()
+ .setGeoDetectionEnabled(false)
+ .build();
+
+ private static final TimeZoneConfiguration CONFIG_GEO_DETECTION_ENABLED =
+ new TimeZoneConfiguration.Builder()
+ .setGeoDetectionEnabled(true)
+ .build();
+
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
private FakeCallback mFakeCallback;
private MockStrategyListener mMockStrategyListener;
@@ -120,7 +131,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testGetCapabilities() {
new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID));
}
@@ -129,7 +140,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testGetConfiguration() {
new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID);
assertTrue(expectedConfiguration.isComplete());
assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID));
@@ -140,20 +151,22 @@ public class TimeZoneDetectorStrategyImplTest {
Script script = new Script();
script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
}
script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_POSSESSED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
}
}
@@ -163,20 +176,22 @@ public class TimeZoneDetectorStrategyImplTest {
Script script = new Script();
script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
}
script.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
}
}
@@ -186,20 +201,22 @@ public class TimeZoneDetectorStrategyImplTest {
Script script = new Script();
script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
}
script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureAutoDetectionEnabled());
+ assertEquals(CAPABILITY_NOT_SUPPORTED, capabilities.getConfigureGeoDetectionEnabled());
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
}
}
@@ -208,42 +225,61 @@ public class TimeZoneDetectorStrategyImplTest {
public void testUpdateConfiguration_unrestricted() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
// Set the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
// Nothing should have happened: it was initialized in this state.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(
- USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ script.verifyConfigurationChangedAndReset(USER_ID,
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED));
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */);
// The settings should have been changed and the StrategyListener onChange() called.
- script.verifyConfigurationChangedAndReset(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.verifyConfigurationChangedAndReset(USER_ID,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
+
+ // Update the configuration to enable geolocation time zone detection.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */);
+
+ // The settings should have been changed and the StrategyListener onChange() called.
+ script.verifyConfigurationChangedAndReset(USER_ID,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
}
@Test
public void testUpdateConfiguration_restricted() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
+
+ // The settings should not have been changed: user shouldn't have the capabilities.
+ script.verifyConfigurationNotChanged();
+
+ // Update the configuration to enable geolocation time zone detection.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -253,16 +289,18 @@ public class TimeZoneDetectorStrategyImplTest {
public void testUpdateConfiguration_autoDetectNotSupported() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
// Try to update the configuration with auto detection disabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
// Update the configuration with auto detection enabled.
- script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, false /* expectedResult */);
// The settings should not have been changed: user shouldn't have the capabilities.
script.verifyConfigurationNotChanged();
@@ -276,7 +314,7 @@ public class TimeZoneDetectorStrategyImplTest {
createEmptySlotIndex2Suggestion();
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
@@ -308,6 +346,10 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
}
+ /**
+ * Telephony suggestions have quality metadata. Ordinarily, low scoring suggestions are not
+ * used, but this is not true if the device's time zone setting is uninitialized.
+ */
@Test
public void testTelephonySuggestionsWhenTimeZoneUninitialized() {
assertTrue(TELEPHONY_SCORE_LOW < TELEPHONY_SCORE_USAGE_THRESHOLD);
@@ -319,7 +361,7 @@ public class TimeZoneDetectorStrategyImplTest {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
// A low quality suggestions will not be taken: The device time zone setting is left
// uninitialized.
@@ -376,16 +418,16 @@ public class TimeZoneDetectorStrategyImplTest {
/**
* Confirms that toggling the auto time zone detection setting has the expected behavior when
- * the strategy is "opinionated".
+ * the strategy is "opinionated" when using telephony auto detection.
*/
@Test
- public void testTogglingAutoTimeZoneDetection() {
+ public void testTogglingAutoDetection_autoTelephony() {
Script script = new Script();
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
// Start with the device in a known state.
script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
TelephonyTimeZoneSuggestion suggestion =
@@ -405,7 +447,8 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting on should cause the device setting to be set.
- script.simulateAutoTimeZoneDetectionEnabled(USER_ID, true);
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED,
+ true /* expectedResult */);
// When time zone detection is already enabled the suggestion (if it scores highly
// enough) should be set immediately.
@@ -422,7 +465,8 @@ public class TimeZoneDetectorStrategyImplTest {
mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests());
// Toggling the time zone setting should off should do nothing.
- script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false)
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Assert internal service state.
@@ -437,7 +481,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testTelephonySuggestionsSingleSlotId() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
@@ -451,8 +495,7 @@ public class TimeZoneDetectorStrategyImplTest {
*/
// Each test case will have the same or lower score than the last.
- ArrayList<TelephonyTestCase> descendingCasesByScore =
- new ArrayList<>(Arrays.asList(TELEPHONY_TEST_CASES));
+ List<TelephonyTestCase> descendingCasesByScore = list(TELEPHONY_TEST_CASES);
Collections.reverse(descendingCasesByScore);
for (TelephonyTestCase testCase : descendingCasesByScore) {
@@ -504,7 +547,7 @@ public class TimeZoneDetectorStrategyImplTest {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
// Initialize the latest suggestions as empty so we don't need to worry about nulls
// below for the first loop.
@@ -583,15 +626,15 @@ public class TimeZoneDetectorStrategyImplTest {
}
/**
- * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing
- * the time zone is actually necessary. This test proves that the service doesn't assume it
- * knows the current setting.
+ * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time
+ * zone is actually necessary. This test proves that the strategy doesn't assume it knows the
+ * current settings.
*/
@Test
- public void testTelephonySuggestionTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting() {
+ public void testTelephonySuggestionStrategyDoesNotAssumeCurrentSetting_autoTelephony() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED));
TelephonyTestCase testCase = newTelephonyTestCase(
MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -609,26 +652,40 @@ public class TimeZoneDetectorStrategyImplTest {
// Toggling time zone detection should set the device time zone only if the current setting
// value is different from the most recent telephony suggestion.
- script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged()
- .simulateAutoTimeZoneDetectionEnabled(USER_ID, true)
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneNotChanged();
// Simulate a user turning auto detection off, a new suggestion being made while auto
// detection is off, and the user turning it on again.
- script.simulateAutoTimeZoneDetectionEnabled(USER_ID, false)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
.simulateTelephonyTimeZoneSuggestion(newYorkSuggestion)
.verifyTimeZoneNotChanged();
// Latest suggestion should be used.
- script.simulateAutoTimeZoneDetectionEnabled(USER_ID, true)
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
.verifyTimeZoneChangedAndReset(newYorkSuggestion);
}
@Test
- public void testManualSuggestion_unrestricted_simulateAutoTimeZoneEnabled() {
+ public void testManualSuggestion_autoDetectionEnabled_autoTelephony() {
+ checkManualSuggestion_autoDetectionEnabled(false /* geoDetectionEnabled */);
+ }
+
+ @Test
+ public void testManualSuggestion_autoDetectionEnabled_autoGeo() {
+ checkManualSuggestion_autoDetectionEnabled(true /* geoDetectionEnabled */);
+ }
+
+ private void checkManualSuggestion_autoDetectionEnabled(boolean geoDetectionEnabled) {
+ TimeZoneConfiguration geoTzEnabledConfig =
+ new TimeZoneConfiguration.Builder()
+ .setGeoDetectionEnabled(geoDetectionEnabled)
+ .build();
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(geoTzEnabledConfig))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -641,7 +698,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -654,7 +711,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -668,7 +725,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is disabled so the manual suggestion should be used.
@@ -682,7 +739,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.RESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Restricted users do not have the capability.
@@ -696,7 +753,7 @@ public class TimeZoneDetectorStrategyImplTest {
public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() {
Script script = new Script()
.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Unrestricted users have the capability.
@@ -707,10 +764,261 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
+ public void testGeoSuggestion_uncertain() {
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ GeolocationTimeZoneSuggestion uncertainSuggestion = createUncertainGeoLocationSuggestion();
+
+ script.simulateGeolocationTimeZoneSuggestion(uncertainSuggestion)
+ .verifyTimeZoneNotChanged();
+
+ // Assert internal service state.
+ assertEquals(uncertainSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ }
+
+ @Test
+ public void testGeoSuggestion_noZones() {
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ GeolocationTimeZoneSuggestion noZonesSuggestion = createGeoLocationSuggestion(list());
+
+ script.simulateGeolocationTimeZoneSuggestion(noZonesSuggestion)
+ .verifyTimeZoneNotChanged();
+
+ // Assert internal service state.
+ assertEquals(noZonesSuggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ }
+
+ @Test
+ public void testGeoSuggestion_oneZone() {
+ GeolocationTimeZoneSuggestion suggestion =
+ createGeoLocationSuggestion(list("Europe/London"));
+
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ script.simulateGeolocationTimeZoneSuggestion(suggestion)
+ .verifyTimeZoneChangedAndReset("Europe/London");
+
+ // Assert internal service state.
+ assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ }
+
+ /**
+ * In the current implementation, the first zone ID is always used unless the device is set to
+ * one of the other options. This is "stickiness" - the device favors the zone it is currently
+ * set to until that unambiguously can't be correct.
+ */
+ @Test
+ public void testGeoSuggestion_multiZone() {
+ GeolocationTimeZoneSuggestion londonOnlySuggestion =
+ createGeoLocationSuggestion(list("Europe/London"));
+ GeolocationTimeZoneSuggestion londonOrParisSuggestion =
+ createGeoLocationSuggestion(list("Europe/Paris", "Europe/London"));
+ GeolocationTimeZoneSuggestion parisOnlySuggestion =
+ createGeoLocationSuggestion(list("Europe/Paris"));
+
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
+ .verifyTimeZoneChangedAndReset("Europe/London");
+ assertEquals(londonOnlySuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
+ // Confirm bias towards the current device zone when there's multiple zones to choose from.
+ script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion)
+ .verifyTimeZoneNotChanged();
+ assertEquals(londonOrParisSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
+ script.simulateGeolocationTimeZoneSuggestion(parisOnlySuggestion)
+ .verifyTimeZoneChangedAndReset("Europe/Paris");
+ assertEquals(parisOnlySuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
+ // Now the suggestion that previously left the device on Europe/London will leave the device
+ // on Europe/Paris.
+ script.simulateGeolocationTimeZoneSuggestion(londonOrParisSuggestion)
+ .verifyTimeZoneNotChanged();
+ assertEquals(londonOrParisSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ }
+
+ /**
+ * Confirms that toggling the auto time zone detection enabled setting has the expected behavior
+ * when the strategy is "opinionated" and "un-opinionated" when in geolocation detection is
+ * enabled.
+ */
+ @Test
+ public void testTogglingAutoDetectionEnabled_autoGeo() {
+ GeolocationTimeZoneSuggestion geolocationSuggestion =
+ createGeoLocationSuggestion(list("Europe/London"));
+ GeolocationTimeZoneSuggestion uncertainGeolocationSuggestion =
+ createUncertainGeoLocationSuggestion();
+ ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
+
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_ENABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion);
+
+ // When time zone detection is not enabled, the time zone suggestion will not be set.
+ script.verifyTimeZoneNotChanged();
+
+ // Assert internal service state.
+ assertEquals(geolocationSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+
+ // Toggling the time zone setting on should cause the device setting to be set.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset("Europe/London");
+
+ // Toggling the time zone setting should off should do nothing because the device is now
+ // set to that time zone.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged()
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged();
+
+ // Now toggle auto time zone setting, and confirm it is opinionated.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ .simulateManualTimeZoneSuggestion(
+ USER_ID, manualSuggestion, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(manualSuggestion)
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset("Europe/London");
+
+ // Now withdraw the geolocation suggestion, and assert the strategy is no longer
+ // opinionated.
+ /* expectedResult */
+ script.simulateGeolocationTimeZoneSuggestion(uncertainGeolocationSuggestion)
+ .verifyTimeZoneNotChanged()
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged()
+ .simulateManualTimeZoneSuggestion(
+ USER_ID, manualSuggestion, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(manualSuggestion)
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged();
+
+ // Assert internal service state.
+ assertEquals(uncertainGeolocationSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ }
+
+ /**
+ * Confirms that changing the geolocation time zone detection enabled setting has the expected
+ * behavior, i.e. immediately recompute the detected time zone using different signals.
+ */
+ @Test
+ public void testChangingGeoDetectionEnabled() {
+ GeolocationTimeZoneSuggestion geolocationSuggestion =
+ createGeoLocationSuggestion(list("Europe/London"));
+ TelephonyTimeZoneSuggestion telephonySuggestion = createTelephonySuggestion(
+ SLOT_INDEX1, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
+ "Europe/Paris");
+
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ // Add suggestions. Nothing should happen as time zone detection is disabled.
+ script.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
+ .verifyTimeZoneNotChanged();
+ script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
+ .verifyTimeZoneNotChanged();
+
+ // Assert internal service state.
+ assertEquals(geolocationSuggestion,
+ mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
+ assertEquals(telephonySuggestion,
+ mTimeZoneDetectorStrategy.getLatestTelephonySuggestion(SLOT_INDEX1).suggestion);
+
+ // Toggling the time zone detection enabled setting on should cause the device setting to be
+ // set from the telephony signal, as we've started with geolocation time zone detection
+ // disabled.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(telephonySuggestion);
+
+ // Changing the detection to enable geo detection should cause the device tz setting to
+ // change to the geo suggestion.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
+
+ // Changing the detection to disable geo detection should cause the device tz setting to
+ // change to the telephony suggestion.
+ script.simulateUpdateConfiguration(
+ USER_ID, CONFIG_GEO_DETECTION_DISABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(telephonySuggestion);
+ }
+
+ /**
+ * The {@link TimeZoneDetectorStrategyImpl.Callback} is left to detect whether changing the time
+ * zone is actually necessary. This test proves that the strategy doesn't assume it knows the
+ * current setting.
+ */
+ @Test
+ public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting_autoGeo() {
+ GeolocationTimeZoneSuggestion losAngelesSuggestion =
+ createGeoLocationSuggestion(list("America/Los_Angeles"));
+ GeolocationTimeZoneSuggestion newYorkSuggestion =
+ createGeoLocationSuggestion(list("America/New_York"));
+
+ Script script = new Script()
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_ENABLED.with(CONFIG_GEO_DETECTION_ENABLED));
+
+ // Initialization.
+ script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
+ .verifyTimeZoneChangedAndReset("America/Los_Angeles");
+ // Suggest it again - it should not be set because it is already set.
+ script.simulateGeolocationTimeZoneSuggestion(losAngelesSuggestion)
+ .verifyTimeZoneNotChanged();
+
+ // Toggling time zone detection should set the device time zone only if the current setting
+ // value is different from the most recent telephony suggestion.
+ /* expectedResult */
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged()
+ .simulateUpdateConfiguration(
+ USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneNotChanged();
+
+ // Simulate a user turning auto detection off, a new suggestion being made while auto
+ // detection is off, and the user turning it on again.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_DISABLED, true /* expectedResult */)
+ .simulateGeolocationTimeZoneSuggestion(newYorkSuggestion)
+ .verifyTimeZoneNotChanged();
+ // Latest suggestion should be used.
+ script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_ENABLED, true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset("America/New_York");
+ }
+
+ @Test
public void testAddDumpable() {
new Script()
.initializeUser(USER_ID, UserCase.UNRESTRICTED,
- CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ CONFIG_AUTO_DISABLED.with(CONFIG_GEO_DETECTION_DISABLED))
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
AtomicBoolean dumpCalled = new AtomicBoolean(false);
@@ -733,6 +1041,15 @@ public class TimeZoneDetectorStrategyImplTest {
return new ManualTimeZoneSuggestion(zoneId);
}
+ private static TelephonyTimeZoneSuggestion createTelephonySuggestion(
+ int slotIndex, @MatchType int matchType, @Quality int quality, String zoneId) {
+ return new TelephonyTimeZoneSuggestion.Builder(slotIndex)
+ .setMatchType(matchType)
+ .setQuality(quality)
+ .setZoneId(zoneId)
+ .build();
+ }
+
private static TelephonyTimeZoneSuggestion createEmptySlotIndex1Suggestion() {
return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX1).build();
}
@@ -741,6 +1058,17 @@ public class TimeZoneDetectorStrategyImplTest {
return new TelephonyTimeZoneSuggestion.Builder(SLOT_INDEX2).build();
}
+ private static GeolocationTimeZoneSuggestion createUncertainGeoLocationSuggestion() {
+ return createGeoLocationSuggestion(null);
+ }
+
+ private static GeolocationTimeZoneSuggestion createGeoLocationSuggestion(
+ @Nullable List<String> zoneIds) {
+ GeolocationTimeZoneSuggestion suggestion = new GeolocationTimeZoneSuggestion(zoneIds);
+ suggestion.addDebugInfo("Test suggestion");
+ return suggestion;
+ }
+
static class FakeCallback implements TimeZoneDetectorStrategyImpl.Callback {
private TimeZoneCapabilities mCapabilities;
@@ -757,7 +1085,8 @@ public class TimeZoneDetectorStrategyImplTest {
TimeZoneConfiguration configuration) {
assertEquals(userId, capabilities.getUserId());
mCapabilities = capabilities;
- assertTrue(configuration.isComplete());
+ assertTrue("Configuration must be complete when initializing, config=" + configuration,
+ configuration.isComplete());
mConfiguration.init(new UserConfiguration(userId, configuration));
}
@@ -790,11 +1119,8 @@ public class TimeZoneDetectorStrategyImplTest {
mConfiguration.set(new UserConfiguration(userId, newConfig));
if (!newConfig.equals(oldConfig)) {
- if (oldConfig.isAutoDetectionEnabled() != newConfig.isAutoDetectionEnabled()) {
- // Simulate what happens when the auto detection enabled configuration is
- // changed.
- mStrategy.handleAutoTimeZoneConfigChanged();
- }
+ // Simulate what happens when the auto detection configuration is changed.
+ mStrategy.handleAutoTimeZoneConfigChanged();
}
}
@@ -804,6 +1130,11 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Override
+ public boolean isGeoDetectionEnabled() {
+ return mConfiguration.getLatest().configuration.isGeoDetectionEnabled();
+ }
+
+ @Override
public boolean isDeviceTimeZoneInitialized() {
return mTimeZoneId.getLatest() != null;
}
@@ -942,32 +1273,33 @@ public class TimeZoneDetectorStrategyImplTest {
* supplied configuration.
*/
private static TimeZoneCapabilities createCapabilities(
- int userId, UserCase userRole, TimeZoneConfiguration configuration) {
- switch (userRole) {
+ int userId, UserCase userCase, TimeZoneConfiguration configuration) {
+ switch (userCase) {
case UNRESTRICTED: {
int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled()
? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED;
return new TimeZoneCapabilities.Builder(userId)
.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
.setSuggestManualTimeZone(suggestManualTimeZoneCapability)
.build();
}
case RESTRICTED: {
return new TimeZoneCapabilities.Builder(userId)
.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
.build();
-
}
case AUTO_DETECT_NOT_SUPPORTED: {
return new TimeZoneCapabilities.Builder(userId)
.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
+ .setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED)
.build();
-
}
default:
- throw new AssertionError(userRole + " not recognized");
+ throw new AssertionError(userCase + " not recognized");
}
}
@@ -978,8 +1310,8 @@ public class TimeZoneDetectorStrategyImplTest {
private class Script {
Script initializeUser(
- @UserIdInt int userId, UserCase userRole, TimeZoneConfiguration configuration) {
- TimeZoneCapabilities capabilities = createCapabilities(userId, userRole, configuration);
+ @UserIdInt int userId, UserCase userCase, TimeZoneConfiguration configuration) {
+ TimeZoneCapabilities capabilities = createCapabilities(userId, userCase, configuration);
mFakeCallback.initializeUser(userId, capabilities, configuration);
return this;
}
@@ -989,27 +1321,24 @@ public class TimeZoneDetectorStrategyImplTest {
return this;
}
- Script simulateAutoTimeZoneDetectionEnabled(@UserIdInt int userId, boolean enabled) {
- TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
- .setAutoDetectionEnabled(enabled)
- .build();
- return simulateUpdateConfiguration(userId, configuration);
- }
-
/**
- * Simulates the time zone detection strategy receiving an updated configuration.
+ * Simulates the time zone detection strategy receiving an updated configuration and checks
+ * the return value.
*/
Script simulateUpdateConfiguration(
- @UserIdInt int userId, TimeZoneConfiguration configuration) {
- mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration);
+ @UserIdInt int userId, TimeZoneConfiguration configuration,
+ boolean expectedResult) {
+ assertEquals(expectedResult,
+ mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration));
return this;
}
/**
- * Simulates the time zone detection strategy receiving a telephony-originated suggestion.
+ * Simulates the time zone detection strategy receiving a geolocation-originated
+ * suggestion.
*/
- Script simulateTelephonyTimeZoneSuggestion(TelephonyTimeZoneSuggestion timeZoneSuggestion) {
- mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion);
+ Script simulateGeolocationTimeZoneSuggestion(GeolocationTimeZoneSuggestion suggestion) {
+ mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(suggestion);
return this;
}
@@ -1024,13 +1353,26 @@ public class TimeZoneDetectorStrategyImplTest {
return this;
}
+ /**
+ * Simulates the time zone detection strategy receiving a telephony-originated suggestion.
+ */
+ Script simulateTelephonyTimeZoneSuggestion(TelephonyTimeZoneSuggestion timeZoneSuggestion) {
+ mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion);
+ return this;
+ }
+
+ /**
+ * Confirms that the device's time zone has not been set by previous actions since the test
+ * state was last reset.
+ */
Script verifyTimeZoneNotChanged() {
mFakeCallback.assertTimeZoneNotChanged();
return this;
}
- Script verifyTimeZoneChangedAndReset(TelephonyTimeZoneSuggestion suggestion) {
- mFakeCallback.assertTimeZoneChangedTo(suggestion.getZoneId());
+ /** Verifies the device's time zone has been set and clears change tracking history. */
+ Script verifyTimeZoneChangedAndReset(String zoneId) {
+ mFakeCallback.assertTimeZoneChangedTo(zoneId);
mFakeCallback.commitAllChanges();
return this;
}
@@ -1041,6 +1383,12 @@ public class TimeZoneDetectorStrategyImplTest {
return this;
}
+ Script verifyTimeZoneChangedAndReset(TelephonyTimeZoneSuggestion suggestion) {
+ mFakeCallback.assertTimeZoneChangedTo(suggestion.getZoneId());
+ mFakeCallback.commitAllChanges();
+ return this;
+ }
+
/**
* Verifies that the configuration has been changed to the expected value.
*/
@@ -1120,4 +1468,8 @@ public class TimeZoneDetectorStrategyImplTest {
mOnConfigurationChangedCalled = false;
}
}
+
+ private static <T> List<T> list(T... values) {
+ return Arrays.asList(values);
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
deleted file mode 100644
index f6c854e23494..000000000000
--- a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.server.slice;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.UiServiceTestCase;
-import com.android.server.slice.SliceManagerService.PackageMatchingCache;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.Supplier;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class PackageMatchingCacheTest extends UiServiceTestCase {
-
- private final Supplier<String> supplier = mock(Supplier.class);
- private final PackageMatchingCache cache = new PackageMatchingCache(supplier);
-
- @Test
- public void testNulls() {
- // Doesn't get for a null input
- cache.matches(null);
- verify(supplier, never()).get();
-
- // Gets once valid input in sent.
- cache.matches("");
- verify(supplier).get();
- }
-
- @Test
- public void testCaching() {
- when(supplier.get()).thenReturn("ret.pkg");
-
- assertTrue(cache.matches("ret.pkg"));
- assertTrue(cache.matches("ret.pkg"));
- assertTrue(cache.matches("ret.pkg"));
-
- verify(supplier, times(1)).get();
- }
-
- @Test
- public void testGetOnFailure() {
- when(supplier.get()).thenReturn("ret.pkg");
- assertTrue(cache.matches("ret.pkg"));
-
- when(supplier.get()).thenReturn("other.pkg");
- assertTrue(cache.matches("other.pkg"));
- verify(supplier, times(2)).get();
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index a4436951f48b..cf1c36c0d243 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -90,8 +90,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
@Test
public void testAddPinCreatesPinned() throws RemoteException {
- doReturn("pkg").when(mService).getDefaultHome(anyInt());
-
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
verify(mService, times(1)).createPinnedSlice(eq(maybeAddUserId(TEST_URI, 0)), anyString());
@@ -99,8 +97,6 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
@Test
public void testRemovePinDestroysPinned() throws RemoteException {
- doReturn("pkg").when(mService).getDefaultHome(anyInt());
-
mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
when(mCreatedSliceState.unpin(eq("pkg"), eq(mToken))).thenReturn(false);
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index 53c69c47d052..eff64a31367a 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -326,6 +326,8 @@ package android.net.wifi {
field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
+ field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3
+ field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2
field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 71f0ab8087ab..1588bf72c969 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1130,7 +1130,9 @@ public class WifiConfiguration implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"RANDOMIZATION_"}, value = {
RANDOMIZATION_NONE,
- RANDOMIZATION_PERSISTENT})
+ RANDOMIZATION_PERSISTENT,
+ RANDOMIZATION_ENHANCED,
+ RANDOMIZATION_AUTO})
public @interface MacRandomizationSetting {}
/**
@@ -1147,14 +1149,30 @@ public class WifiConfiguration implements Parcelable {
public static final int RANDOMIZATION_PERSISTENT = 1;
/**
+ * Use a randomly generated MAC address for connections to this network.
+ * This option does not persist the randomized MAC address.
+ * @hide
+ */
+ @SystemApi
+ public static final int RANDOMIZATION_ENHANCED = 2;
+
+ /**
+ * Let the wifi framework automatically decide the MAC randomization strategy.
+ * @hide
+ */
+ @SystemApi
+ public static final int RANDOMIZATION_AUTO = 3;
+
+ /**
* Level of MAC randomization for this network.
- * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
- * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}.
+ * One of {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_AUTO},
+ * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_ENHANCED}.
+ * By default this field is set to {@link #RANDOMIZATION_AUTO}.
* @hide
*/
@SystemApi
@MacRandomizationSetting
- public int macRandomizationSetting = RANDOMIZATION_PERSISTENT;
+ public int macRandomizationSetting = RANDOMIZATION_AUTO;
/**
* @hide