summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp13
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java12
-rw-r--r--api/current.txt4
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp10
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp18
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h7
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp10
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h6
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp17
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h11
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp41
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h54
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp28
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h11
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp219
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h5
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp12
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp21
-rw-r--r--core/java/android/app/ApplicationPackageManager.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java14
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java8
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java11
-rw-r--r--core/java/android/net/LinkProperties.java47
-rwxr-xr-xcore/java/android/os/Build.java3
-rw-r--r--core/java/android/os/HwParcel.java52
-rw-r--r--core/java/android/util/ArraySet.java13
-rw-r--r--core/java/android/util/FeatureFlagUtils.java1
-rw-r--r--core/jni/Android.bp2
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values/config.xml8
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--location/java/android/location/LocationManager.java87
-rw-r--r--location/java/android/location/LocationProvider.java20
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java110
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp19
-rw-r--r--mime/Android.bp33
-rw-r--r--mime/java/android/content/type/DefaultMimeMapFactory.java63
-rw-r--r--packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java28
-rw-r--r--packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java210
-rw-r--r--packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java75
-rw-r--r--packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java387
-rw-r--r--packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java83
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java5
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java7
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java7
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java155
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java7
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java (renamed from core/java/android/content/pm/PackageManagerInternal.java)2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java13
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/integrity/model/EvaluationOutcome.java67
-rw-r--r--services/core/java/com/android/server/integrity/model/OpenFormula.java39
-rw-r--r--services/core/java/com/android/server/integrity/model/Rule.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageList.java (renamed from core/java/android/content/pm/PackageList.java)3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java13
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java37
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java14
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java17
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsPersister.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java95
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java7
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java20
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java22
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java2
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java14
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java25
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java2
103 files changed, 2117 insertions, 698 deletions
diff --git a/Android.bp b/Android.bp
index a1061681358f..1eba3e2711f1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -953,6 +953,7 @@ stubs_defaults {
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
"test-mock/src/**/*.java",
@@ -1017,6 +1018,7 @@ stubs_defaults {
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
":jobscheduler-framework-source",
@@ -1570,3 +1572,14 @@ filegroup {
],
}
+// Avoid including Parcelable classes as we don't want to have two copies of
+// Parcelable cross the process.
+filegroup {
+ name: "framework-cellbroadcast-shared-srcs",
+ srcs: [
+ "core/java/android/util/LocalLog.java",
+ "core/java/android/util/Slog.java",
+ "core/java/com/android/internal/util/State.java",
+ "core/java/com/android/internal/util/StateMachine.java",
+ ],
+} \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index fe7b4aecb792..7c472a9813aa 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1851,16 +1851,6 @@ public class AppStandbyController implements AppStandbyInternal {
* Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
*/
private class SettingsObserver extends ContentObserver {
- /**
- * This flag has been used to disable app idle on older builds with bug b/26355386.
- */
- @Deprecated
- private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
- @Deprecated
- private static final String KEY_IDLE_DURATION = "idle_duration2";
- @Deprecated
- private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
-
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_WINDOW = "parole_window";
private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1995,7 +1985,7 @@ public class AppStandbyController implements AppStandbyInternal {
: DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
- KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
+ KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
COMPRESS_TIME ? ONE_MINUTE
: DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); // TODO
diff --git a/api/current.txt b/api/current.txt
index 8733aab02b00..dda327f19f41 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25387,6 +25387,7 @@ package android.media {
method public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtTime(long, int);
+ method public android.graphics.Bitmap getFrameAtTime(long, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
@@ -25396,6 +25397,7 @@ package android.media {
method public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getPrimaryImage();
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
+ method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
method public void release();
method public void setDataSource(String) throws java.lang.IllegalArgumentException;
method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
@@ -28809,6 +28811,7 @@ package android.net {
method @Nullable public String getPrivateDnsServerName();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
method public boolean isPrivateDnsActive();
+ method public boolean isWakeOnLanSupported();
method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setDomains(@Nullable String);
method public void setHttpProxy(@Nullable android.net.ProxyInfo);
@@ -47912,6 +47915,7 @@ package android.util {
ctor public ArraySet(int);
ctor public ArraySet(android.util.ArraySet<E>);
ctor public ArraySet(java.util.Collection<? extends E>);
+ ctor public ArraySet(@Nullable E[]);
method public boolean add(E);
method public void addAll(android.util.ArraySet<? extends E>);
method public boolean addAll(java.util.Collection<? extends E>);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 1d0d2fb70a9d..b5c8e35accad 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -37,6 +37,7 @@ using std::map;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -67,8 +68,13 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard) {
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index b4a910c6f410..61913c71cdcc 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -42,7 +42,11 @@ class CountMetricProducer : public MetricProducer {
public:
CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t timeBaseNs, const int64_t startTimeNs);
+ const int64_t timeBaseNs, const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~CountMetricProducer();
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index d7b46d1858cc..31b90f3b13b1 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -36,6 +36,7 @@ using android::util::ProtoOutputStream;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -62,14 +63,15 @@ const int FIELD_ID_BUCKET_NUM = 4;
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric,
- const int conditionIndex, const size_t startIndex,
- const size_t stopIndex, const size_t stopAllIndex,
- const bool nesting,
- const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions,
- const int64_t timeBaseNs, const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+DurationMetricProducer::DurationMetricProducer(
+ const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
+ const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
+ const bool nesting, const sp<ConditionWizard>& wizard,
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 56c9fd68eac5..0592b1808f52 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -42,7 +42,12 @@ public:
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs);
+ const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~DurationMetricProducer();
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 96133bd0a38d..a60a9161bdbb 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -36,6 +36,7 @@ using std::map;
using std::string;
using std::unordered_map;
using std::vector;
+using std::shared_ptr;
namespace android {
namespace os {
@@ -54,8 +55,13 @@ const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
const int conditionIndex,
const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs)
- : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard) {
+ const int64_t startTimeNs,
+ const unordered_map<int, shared_ptr<Activation>>&
+ eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 74e6bc845c04..aab53c8b6816 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -35,7 +35,11 @@ class EventMetricProducer : public MetricProducer {
public:
EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric,
const int conditionIndex, const sp<ConditionWizard>& wizard,
- const int64_t startTimeNs);
+ const int64_t startTimeNs,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~EventMetricProducer();
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index efd05dcb04f1..e409b6fbb9e9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -72,8 +72,11 @@ GaugeMetricProducer::GaugeMetricProducer(
const sp<ConditionWizard>& wizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+ const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
+ eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -133,8 +136,11 @@ GaugeMetricProducer::GaugeMetricProducer(
mBucketSizeNs);
}
- // Adjust start for partial bucket
+ // Adjust start for partial first bucket and then pull if needed
mCurrentBucketStartTimeNs = startTimeNs;
+ if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
+ }
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
(long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
@@ -295,11 +301,6 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
}
}
-void GaugeMetricProducer::prepareFirstBucketLocked() {
- if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
- }
-}
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index a612adf8a38b..dfe1d56c61c7 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -58,11 +58,14 @@ class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex,const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int triggerAtomId, const int atomId,
const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~GaugeMetricProducer();
@@ -125,8 +128,6 @@ private:
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void pullAndMatchEventsLocked(const int64_t timestampNs);
const int mWhatMatcherIndex;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 1ab4fdf6e90c..3426a195a748 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -40,6 +40,29 @@ const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
+MetricProducer::MetricProducer(
+ const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap)
+ : mMetricId(metricId),
+ mConfigKey(key),
+ mTimeBaseNs(timeBaseNs),
+ mCurrentBucketStartTimeNs(timeBaseNs),
+ mCurrentBucketNum(0),
+ mCondition(initialCondition(conditionIndex)),
+ mConditionTrackerIndex(conditionIndex),
+ mConditionSliced(false),
+ mWizard(wizard),
+ mContainANYPositionInDimensionsInWhat(false),
+ mSliceByPositionALL(false),
+ mHasLinksToAllConditionDimensionsInTracker(false),
+ mEventActivationMap(eventActivationMap),
+ mEventDeactivationMap(eventDeactivationMap),
+ mIsActive(mEventActivationMap.empty()) {
+ }
+
void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
if (!mIsActive) {
return;
@@ -97,24 +120,6 @@ void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
}
}
-void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex) {
- std::lock_guard<std::mutex> lock(mMutex);
- // When a metric producer does not depend on any activation, its mIsActive is true.
- // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
- // change.
- if (mEventActivationMap.empty()) {
- mIsActive = false;
- }
- std::shared_ptr<Activation> activation =
- std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC);
- mEventActivationMap.emplace(activationTrackerIndex, activation);
- if (-1 != deactivationTrackerIndex) {
- auto& deactivationList = mEventDeactivationMap[deactivationTrackerIndex];
- deactivationList.push_back(activation);
- }
-}
-
void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
auto it = mEventActivationMap.find(activationTrackerIndex);
if (it == mEventActivationMap.end()) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index fdbdc83fb66e..1e1eb69aa8f0 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -69,6 +69,19 @@ enum DumpLatency {
NO_TIME_CONSTRAINTS = 2
};
+struct Activation {
+ Activation(const ActivationType& activationType, const int64_t ttlNs)
+ : ttl_ns(ttlNs),
+ start_ns(0),
+ state(ActivationState::kNotActive),
+ activationType(activationType) {}
+
+ const int64_t ttl_ns;
+ int64_t start_ns;
+ ActivationState state;
+ const ActivationType activationType;
+};
+
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -76,21 +89,10 @@ enum DumpLatency {
class MetricProducer : public virtual PackageInfoListener {
public:
MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
- const int conditionIndex, const sp<ConditionWizard>& wizard)
- : mMetricId(metricId),
- mConfigKey(key),
- mTimeBaseNs(timeBaseNs),
- mCurrentBucketStartTimeNs(timeBaseNs),
- mCurrentBucketNum(0),
- mCondition(initialCondition(conditionIndex)),
- mConditionTrackerIndex(conditionIndex),
- mConditionSliced(false),
- mWizard(wizard),
- mContainANYPositionInDimensionsInWhat(false),
- mSliceByPositionALL(false),
- mHasLinksToAllConditionDimensionsInTracker(false),
- mIsActive(true) {
- }
+ const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap);
virtual ~MetricProducer(){};
@@ -188,11 +190,6 @@ public:
dropDataLocked(dropTimeNs);
}
- void prepareFirstBucket() {
- std::lock_guard<std::mutex> lock(mMutex);
- prepareFirstBucketLocked();
- }
-
void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMutex);
loadActiveMetricLocked(activeMetric, currentTimeNs);
@@ -215,9 +212,6 @@ public:
void flushIfExpire(int64_t elapsedTimestampNs);
- void addActivation(int activationTrackerIndex, const ActivationType& activationType,
- int64_t ttl_seconds, int deactivationTrackerIndex = -1);
-
void writeActiveMetricToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
@@ -310,7 +304,6 @@ protected:
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
- virtual void prepareFirstBucketLocked() {};
void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
void cancelEventActivationLocked(int deactivationTrackerIndex);
@@ -379,19 +372,6 @@ protected:
mutable std::mutex mMutex;
- struct Activation {
- Activation(const ActivationType& activationType, const int64_t ttlNs)
- : ttl_ns(ttlNs),
- start_ns(0),
- state(ActivationState::kNotActive),
- activationType(activationType) {}
-
- const int64_t ttl_ns;
- int64_t start_ns;
- ActivationState state;
- const ActivationType activationType;
- };
-
// When the metric producer has multiple activations, these activations are ORed to determine
// whether the metric producer is ready to generate metrics.
std::unordered_map<int, std::shared_ptr<Activation>> mEventActivationMap;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index bc1602497c39..7fe5a834f412 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -81,8 +81,11 @@ ValueMetricProducer::ValueMetricProducer(
const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
- const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard),
+ const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
+ const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard,
+ eventActivationMap, eventDeactivationMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
@@ -108,7 +111,7 @@ ValueMetricProducer::ValueMetricProducer(
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
- // Condition timer will be set in prepareFirstBucketLocked.
+ // Condition timer will be set later within the constructor after pulling events
mConditionTimer(false, timeBaseNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
@@ -154,6 +157,15 @@ ValueMetricProducer::ValueMetricProducer(
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
+
+ // Kicks off the puller immediately if condition is true and diff based.
+ if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
+ pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+ }
+ // Now that activations are processed, start the condition timer if needed.
+ mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
+ mCurrentBucketStartTimeNs);
+
VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
}
@@ -165,16 +177,6 @@ ValueMetricProducer::~ValueMetricProducer() {
}
}
-void ValueMetricProducer::prepareFirstBucketLocked() {
- // Kicks off the puller immediately if condition is true and diff based.
- if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
- pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
- }
- // Now that activations are processed, start the condition timer if needed.
- mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
- mCurrentBucketStartTimeNs);
-}
-
void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 739f6ef07cc4..d7cd397da2c0 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -54,10 +54,13 @@ class ValueMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric,
const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager);
+ const sp<StatsPullerManager>& pullerManager,
+ const std::unordered_map<int, std::shared_ptr<Activation>>&
+ eventActivationMap = {},
+ const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
+ eventDeactivationMap = {});
virtual ~ValueMetricProducer();
@@ -116,8 +119,6 @@ private:
void flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) override;
- void prepareFirstBucketLocked() override;
-
void dropDataLocked(const int64_t dropTimeNs) override;
// Calculate previous bucket end time based on current time.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 40484f4fb86b..0fee71e1fe2c 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "metrics_manager_util.h"
+#include "MetricProducer.h"
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
@@ -137,6 +138,62 @@ bool handleMetricWithConditions(
return true;
}
+// Validates a metricActivation and populates state.
+// EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
+// 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 unordered_map<int64_t, int>& metricToActivationMap,
+ const unordered_map<int64_t, int>& logTrackerMap,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation,
+ unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
+ unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
+ // Check if metric has an associated activation
+ auto itr = metricToActivationMap.find(metricId);
+ if (itr == metricToActivationMap.end()) return true;
+
+ int activationIndex = itr->second;
+ const MetricActivation& metricActivation = config.metric_activation(activationIndex);
+
+ for (int i = 0; i < metricActivation.event_activation_size(); i++) {
+ const EventActivation& activation = metricActivation.event_activation(i);
+
+ auto itr = logTrackerMap.find(activation.atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event activation.");
+ 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);
+
+ int atomMatcherIndex = itr->second;
+ activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
+ eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
+
+ if (activation.has_deactivation_atom_matcher_id()) {
+ itr = logTrackerMap.find(activation.deactivation_atom_matcher_id());
+ if (itr == logTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event deactivation.");
+ return false;
+ }
+ int deactivationAtomMatcherIndex = itr->second;
+ deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
+ eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
+ }
+ }
+
+ metricsWithActivation.push_back(metricIndex);
+ return true;
+}
+
bool initLogTrackers(const StatsdConfig& config, const UidMap& uidMap,
unordered_map<int64_t, int>& logTrackerMap,
vector<sp<LogMatchingTracker>>& allAtomMatchers, set<int>& allTagIds) {
@@ -293,16 +350,33 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& conditionToMetricMap,
- unordered_map<int, std::vector<int>>& trackerToMetricMap,
- unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
+ unordered_map<int, vector<int>>& conditionToMetricMap,
+ unordered_map<int, vector<int>>& trackerToMetricMap,
+ unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds,
+ unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
+ unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
- config.event_metric_size() + config.value_metric_size();
+ config.event_metric_size() + config.gauge_metric_size() +
+ config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
StatsPullerManager statsPullerManager;
+ // Construct map from metric id to metric activation index. The map will be used to determine
+ // the metric activation corresponding to a metric.
+ unordered_map<int64_t, int> metricToActivationMap;
+ for (int i = 0; i < config.metric_activation_size(); i++) {
+ 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);
+ return false;
+ }
+ metricToActivationMap.insert({metricId, i});
+ }
+
// Build MetricProducers for each metric defined in config.
// build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
@@ -337,8 +411,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
- sp<MetricProducer> countProducer =
- new CountMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs);
+ 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);
+ if (!success) return false;
+
+ sp<MetricProducer> countProducer = new CountMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(countProducer);
}
@@ -406,9 +489,18 @@ 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);
+ if (!success) return false;
+
sp<MetricProducer> durationMetric = new DurationMetricProducer(
key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
- trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs, currentTimeNs);
+ trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs,
+ currentTimeNs, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(durationMetric);
}
@@ -443,8 +535,17 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
}
- sp<MetricProducer> eventMetric =
- new EventMetricProducer(key, metric, conditionIndex, wizard, timeBaseTimeNs);
+ 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);
+ if (!success) return false;
+
+ sp<MetricProducer> eventMetric = new EventMetricProducer(
+ key, metric, conditionIndex, wizard, timeBaseTimeNs, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(eventMetric);
}
@@ -500,9 +601,18 @@ 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);
+ if (!success) return false;
+
sp<MetricProducer> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager, eventActivationMap,
+ eventDeactivationMap);
allMetricProducers.push_back(valueProducer);
}
@@ -586,10 +696,19 @@ 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);
+ if (!success) return false;
+
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
key, metric, conditionIndex, wizard,
trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager);
+ timeBaseTimeNs, currentTimeNs, pullerManager,
+ eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -707,73 +826,6 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
return true;
}
-bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
- const int64_t currentTimeNs,
- const unordered_map<int64_t, int> &logEventTrackerMap,
- const unordered_map<int64_t, int> &metricProducerMap,
- vector<sp<MetricProducer>>& allMetricProducers,
- unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
- unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
- vector<int>& metricsWithActivation) {
- for (int i = 0; i < config.metric_activation_size(); ++i) {
- const MetricActivation& metric_activation = config.metric_activation(i);
- auto itr = metricProducerMap.find(metric_activation.metric_id());
- if (itr == metricProducerMap.end()) {
- ALOGE("Metric id not found in metric activation: %lld",
- (long long)metric_activation.metric_id());
- return false;
- }
- const int metricTrackerIndex = itr->second;
- if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
- ALOGE("Invalid metric tracker index.");
- return false;
- }
- const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex];
- metricsWithActivation.push_back(metricTrackerIndex);
- for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
- const EventActivation& activation = metric_activation.event_activation(j);
- auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
- if (logTrackerIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event activation.");
- return false;
- }
- const int atomMatcherIndex = logTrackerIt->second;
- activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
- metricTrackerIndex);
-
- ActivationType activationType;
- if (activation.has_activation_type()) {
- activationType = activation.activation_type();
- } else {
- activationType = metric_activation.activation_type();
- }
-
- if (activation.has_deactivation_atom_matcher_id()) {
- auto deactivationAtomMatcherIt =
- logEventTrackerMap.find(activation.deactivation_atom_matcher_id());
- if (deactivationAtomMatcherIt == logEventTrackerMap.end()) {
- ALOGE("Atom matcher not found for event deactivation.");
- return false;
- }
- const int deactivationMatcherIndex = deactivationAtomMatcherIt->second;
- deactivationAtomTrackerToMetricMap[deactivationMatcherIndex]
- .push_back(metricTrackerIndex);
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(),
- deactivationMatcherIndex);
- } else {
- metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds());
- }
- }
- }
- return true;
-}
-
-void prepareFirstBucket(const vector<sp<MetricProducer>>& allMetricProducers) {
- for (const auto& metric: allMetricProducers) {
- metric->prepareFirstBucket();
- }
-}
-
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -810,7 +862,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
if (!initMetrics(key, config, timeBaseNs, currentTimeNs, uidMap, pullerManager, logTrackerMap,
conditionTrackerMap, allAtomMatchers, allConditionTrackers, allMetricProducers,
conditionToMetricMap, trackerToMetricMap, metricProducerMap,
- noReportMetricIds)) {
+ noReportMetricIds, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
ALOGE("initMetricProducers failed");
return false;
}
@@ -824,14 +877,6 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initAlarms failed");
return false;
}
- if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
- allMetricProducers, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
- ALOGE("initMetricActivations failed");
- return false;
- }
-
- prepareFirstBucket(allMetricProducers);
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 3704969039c4..3802948f64da 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -91,7 +91,10 @@ bool initMetrics(
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
- std::set<int64_t>& noReportMetricIds);
+ std::set<int64_t>& noReportMetricIds,
+ std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+ std::vector<int>& metricsWithActivation);
// Initialize MetricsManager from StatsdConfig.
// Parameters are the members of MetricsManager. See MetricsManager for declaration.
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 47c21aa8f1df..b027e8e687db 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -79,8 +79,6 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
@@ -126,8 +124,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
-
vector<shared_ptr<LogEvent>> allData;
allData.clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
@@ -211,7 +207,6 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -303,7 +298,6 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -370,7 +364,6 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -431,7 +424,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -521,7 +513,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- gaugeProducer.prepareFirstBucket();
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -572,7 +563,6 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
Alert alert;
alert.set_id(101);
@@ -681,7 +671,6 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -766,7 +755,6 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 2262c76e64f9..4b9d0c0ca718 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -105,7 +105,6 @@ class ValueMetricProducerTestHelper {
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
return valueProducer;
}
@@ -125,7 +124,6 @@ class ValueMetricProducerTestHelper {
new ValueMetricProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
valueProducer->mCondition = ConditionState::kFalse;
return valueProducer;
}
@@ -169,7 +167,6 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, startTimeBase,
22, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -199,7 +196,6 @@ TEST(ValueMetricProducerTest, TestFirstBucket) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1, 5,
600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
- valueProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, valueProducer.mCurrentBucketNum);
@@ -381,7 +377,6 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -670,7 +665,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -728,7 +722,6 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -779,7 +772,6 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -854,7 +846,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -897,7 +888,6 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
@@ -972,7 +962,6 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -1269,7 +1258,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1314,7 +1302,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1361,7 +1348,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1412,7 +1398,6 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1458,7 +1443,6 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -1532,7 +1516,6 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
- valueProducer.prepareFirstBucket();
shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event1->write(1);
@@ -2081,7 +2064,6 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucket2StartTimeNs,
bucket2StartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
// Event should be skipped since it is from previous bucket.
@@ -2862,7 +2844,6 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
@@ -2905,7 +2886,6 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -2969,7 +2949,6 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
- valueProducer.prepareFirstBucket();
ProtoOutputStream output;
std::set<string> strSet;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a2013075b379..86bf20a57eec 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3169,6 +3169,15 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public String getSetupWizardPackageName() {
+ try {
+ return mPM.getSetupWizardPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public String getIncidentReportApproverPackageName() {
try {
return mPM.getIncidentReportApproverPackageName();
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index b873be3e7042..713126ee9341 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -24,6 +24,10 @@ import java.util.List;
/**
* Device policy manager local system service interface.
*
+ * Maintenance note: if you need to expose information from DPMS to lower level services such as
+ * PM/UM/AM/etc, then exposing it from DevicePolicyManagerInternal is not safe because it may cause
+ * lock order inversion. Consider using {@link DevicePolicyCache} instead.
+ *
* @hide Only for use within the system server.
*/
public abstract class DevicePolicyManagerInternal {
@@ -81,6 +85,16 @@ public abstract class DevicePolicyManagerInternal {
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
+ * Checks if an app with given uid is the active supervision admin.
+ *
+ * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
+ *
+ * @param uid App uid.
+ * @return true if the uid is the active supervision app.
+ */
+ public abstract boolean isActiveSupervisionApp(int uid);
+
+ /**
* Creates an intent to show the admin support dialog to say that an action is disallowed by
* the device/profile owner.
*
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 656f474f72ce..1f13a1e13d13 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -801,8 +801,8 @@ public final class UsageStatsManager {
* {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
* being registered with a {@code timeUsed} equal to or greater than
* {@code timeLimit}.
- * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
- * permissions.
+ * @throws SecurityException if the caller is neither the active supervision app nor does it
+ * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions.
* @hide
*/
@SystemApi
@@ -827,8 +827,8 @@ public final class UsageStatsManager {
* an observer that was already unregistered or never registered will have no effect.
*
* @param observerId The id of the observer that was previously registered.
- * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
- * permissions.
+ * @throws SecurityException if the caller is neither the active supervision app nor does it
+ * have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions.
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4d7c43ace923..19d8edfa3884 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -686,6 +686,8 @@ interface IPackageManager {
String getSystemCaptionsServicePackageName();
+ String getSetupWizardPackageName();
+
String getIncidentReportApproverPackageName();
boolean isPackageStateProtected(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fd14d235a044..9513ce802813 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -7427,6 +7427,17 @@ public abstract class PackageManager {
}
/**
+ * @return the system defined setup wizard package name, or null if there's none.
+ *
+ * @hide
+ */
+ @Nullable
+ public String getSetupWizardPackageName() {
+ throw new UnsupportedOperationException(
+ "getSetupWizardPackageName not implemented in subclass");
+ }
+
+ /**
* @return the incident report approver app package name, or null if it's not defined
* by the OEM.
*
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index d3f48acdd40e..3ec0aeac472b 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -68,6 +68,7 @@ public final class LinkProperties implements Parcelable {
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
private String mTcpBufferSizes;
private IpPrefix mNat64Prefix;
+ private boolean mWakeOnLanSupported;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -193,6 +194,7 @@ public final class LinkProperties implements Parcelable {
setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
mNat64Prefix = source.mNat64Prefix;
+ mWakeOnLanSupported = source.mWakeOnLanSupported;
}
}
@@ -852,6 +854,7 @@ public final class LinkProperties implements Parcelable {
mMtu = 0;
mTcpBufferSizes = null;
mNat64Prefix = null;
+ mWakeOnLanSupported = false;
}
/**
@@ -913,6 +916,10 @@ public final class LinkProperties implements Parcelable {
resultJoiner.add("MTU:");
resultJoiner.add(Integer.toString(mMtu));
+ if (mWakeOnLanSupported) {
+ resultJoiner.add("WakeOnLanSupported: true");
+ }
+
if (mTcpBufferSizes != null) {
resultJoiner.add("TcpBufferSizes:");
resultJoiner.add(mTcpBufferSizes);
@@ -1425,6 +1432,37 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Compares this {@code LinkProperties} WakeOnLan supported against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalWakeOnLan(LinkProperties target) {
+ return isWakeOnLanSupported() == target.isWakeOnLanSupported();
+ }
+
+ /**
+ * Set whether the network interface supports WakeOnLAN
+ *
+ * @param supported WakeOnLAN supported value
+ *
+ * @hide
+ */
+ public void setWakeOnLanSupported(boolean supported) {
+ mWakeOnLanSupported = supported;
+ }
+
+ /**
+ * Returns whether the network interface supports WakeOnLAN
+ *
+ * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
+ */
+ public boolean isWakeOnLanSupported() {
+ return mWakeOnLanSupported;
+ }
+
+ /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
@@ -1461,7 +1499,8 @@ public final class LinkProperties implements Parcelable {
&& isIdenticalStackedLinks(target)
&& isIdenticalMtu(target)
&& isIdenticalTcpBufferSizes(target)
- && isIdenticalNat64Prefix(target);
+ && isIdenticalNat64Prefix(target)
+ && isIdenticalWakeOnLan(target);
}
/**
@@ -1577,7 +1616,8 @@ public final class LinkProperties implements Parcelable {
+ (mUsePrivateDns ? 57 : 0)
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
- + Objects.hash(mNat64Prefix);
+ + Objects.hash(mNat64Prefix)
+ + (mWakeOnLanSupported ? 71 : 0);
}
/**
@@ -1622,6 +1662,8 @@ public final class LinkProperties implements Parcelable {
ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
dest.writeList(stackedLinks);
+
+ dest.writeBoolean(mWakeOnLanSupported);
}
/**
@@ -1677,6 +1719,7 @@ public final class LinkProperties implements Parcelable {
for (LinkProperties stackedLink: stackedLinks) {
netProp.addStackedLink(stackedLink);
}
+ netProp.setWakeOnLanSupported(in.readBoolean());
return netProp;
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index b3125d89a1a7..6a709b56f35a 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -243,7 +243,8 @@ public class Build {
public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", "");
/**
- * The user-visible security patch level.
+ * The user-visible security patch level. This value represents the date when the device
+ * most recently applied a security patch.
*/
public static final String SECURITY_PATCH = SystemProperties.get(
"ro.build.version.security_patch", "");
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index cfb582ef442e..5e8929c6c999 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -23,6 +23,8 @@ import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import dalvik.annotation.optimization.FastNative;
+
import libcore.util.NativeAllocationRegistry;
import java.lang.annotation.Retention;
@@ -72,46 +74,54 @@ public class HwParcel {
/**
* Writes an interface token into the parcel used to verify that
- * a transaction has made it to the write type of interface.
+ * a transaction has made it to the right type of interface.
*
* @param interfaceName fully qualified name of interface message
* is being sent to.
*/
+ @FastNative
public native final void writeInterfaceToken(String interfaceName);
/**
* Writes a boolean value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeBool(boolean val);
/**
* Writes a byte value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt8(byte val);
/**
* Writes a short value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt16(short val);
/**
* Writes a int value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt32(int val);
/**
* Writes a long value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt64(long val);
/**
* Writes a float value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeFloat(float val);
/**
* Writes a double value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeDouble(double val);
/**
* Writes a String value to the end of the parcel.
@@ -120,6 +130,7 @@ public class HwParcel {
*
* @param val to write
*/
+ @FastNative
public native final void writeString(String val);
/**
* Writes a native handle (without duplicating the underlying
@@ -127,42 +138,50 @@ public class HwParcel {
*
* @param val to write
*/
+ @FastNative
public native final void writeNativeHandle(@Nullable NativeHandle val);
/**
* Writes an array of boolean values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeBoolVector(boolean[] val);
/**
* Writes an array of byte values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt8Vector(byte[] val);
/**
* Writes an array of short values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt16Vector(short[] val);
/**
* Writes an array of int values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt32Vector(int[] val);
/**
* Writes an array of long values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt64Vector(long[] val);
/**
* Writes an array of float values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeFloatVector(float[] val);
/**
* Writes an array of double values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeDoubleVector(double[] val);
/**
* Writes an array of String values to the end of the parcel.
@@ -171,6 +190,7 @@ public class HwParcel {
*
* @param val to write
*/
+ @FastNative
private native final void writeStringVector(String[] val);
/**
* Writes an array of native handles to the end of the parcel.
@@ -179,6 +199,7 @@ public class HwParcel {
*
* @param val array of {@link NativeHandle} objects to write
*/
+ @FastNative
private native final void writeNativeHandleVector(NativeHandle[] val);
/**
@@ -299,6 +320,7 @@ public class HwParcel {
* Write a hwbinder object to the end of the parcel.
* @param binder value to write
*/
+ @FastNative
public native final void writeStrongBinder(IHwBinder binder);
/**
@@ -314,48 +336,56 @@ public class HwParcel {
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final boolean readBool();
/**
* Reads a byte value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final byte readInt8();
/**
* Reads a short value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final short readInt16();
/**
* Reads a int value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final int readInt32();
/**
* Reads a long value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final long readInt64();
/**
* Reads a float value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final float readFloat();
/**
* Reads a double value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final double readDouble();
/**
* Reads a String value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final String readString();
/**
* Reads a native handle (without duplicating the underlying file
@@ -366,6 +396,7 @@ public class HwParcel {
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readNativeHandle();
/**
* Reads an embedded native handle (without duplicating the underlying
@@ -379,6 +410,7 @@ public class HwParcel {
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readEmbeddedNativeHandle(
long parentHandle, long offset);
@@ -387,54 +419,63 @@ public class HwParcel {
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final boolean[] readBoolVectorAsArray();
/**
* Reads an array of byte values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final byte[] readInt8VectorAsArray();
/**
* Reads an array of short values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final short[] readInt16VectorAsArray();
/**
* Reads an array of int values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final int[] readInt32VectorAsArray();
/**
* Reads an array of long values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final long[] readInt64VectorAsArray();
/**
* Reads an array of float values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final float[] readFloatVectorAsArray();
/**
* Reads an array of double values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final double[] readDoubleVectorAsArray();
/**
* Reads an array of String values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final String[] readStringVectorAsArray();
/**
* Reads an array of native handles from the parcel.
* @return array of {@link NativeHandle} objects
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final NativeHandle[] readNativeHandleAsArray();
/**
@@ -537,6 +578,7 @@ public class HwParcel {
* @return binder object read from parcel or null if no binder can be read
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final IHwBinder readStrongBinder();
/**
@@ -544,6 +586,7 @@ public class HwParcel {
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final HwBlob readBuffer(long expectedSize);
/**
@@ -559,6 +602,7 @@ public class HwParcel {
* @throws NullPointerException if the transaction specified the blob to be null
* but nullable is false
*/
+ @FastNative
public native final HwBlob readEmbeddedBuffer(
long expectedSize, long parentHandle, long offset,
boolean nullable);
@@ -567,26 +611,31 @@ public class HwParcel {
* Write a buffer into the transaction.
* @param blob blob to write into the parcel.
*/
+ @FastNative
public native final void writeBuffer(HwBlob blob);
/**
* Write a status value into the blob.
* @param status value to write
*/
+ @FastNative
public native final void writeStatus(int status);
/**
* @throws IllegalArgumentException if a success vaue cannot be read
* @throws RemoteException if success value indicates a transaction error
*/
+ @FastNative
public native final void verifySuccess();
/**
* Should be called to reduce memory pressure when this object no longer needs
* to be written to.
*/
+ @FastNative
public native final void releaseTemporaryStorage();
/**
* Should be called when object is no longer needed to reduce possible memory
* pressure if the Java GC does not get to this object in time.
*/
+ @FastNative
public native final void release();
/**
@@ -597,6 +646,7 @@ public class HwParcel {
// Returns address of the "freeFunction".
private static native final long native_init();
+ @FastNative
private native final void native_setup(boolean allocate);
static {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 44c5af20d891..4dda709f285d 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -16,6 +16,7 @@
package android.util;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -329,6 +330,18 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
}
/**
+ * Create a new ArraySet with items from the given array
+ */
+ public ArraySet(@Nullable E[] array) {
+ this();
+ if (array != null) {
+ for (E value : array) {
+ add(value);
+ }
+ }
+ }
+
+ /**
* Make the array map empty. All storage is released.
*/
@Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b66764e81e8f..1be57dd489cf 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -59,6 +59,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
+ DEFAULT_FLAGS.put("settings_work_profile", "false");
}
/**
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 0505fe30c55c..0feab7f61918 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -257,8 +257,6 @@ cc_library_shared {
"libnativeloader_lazy",
"libmemunreachable",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libvintf",
"libnativewindow",
"libdl",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 18f8d7b04c3f..b030b33daf5e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -798,7 +798,7 @@
broadcast module. This is required in order to bind to the cell broadcast service, and
ensures that only the system can forward messages to it.
- <p>Protection level: signature|privileged
+ <p>Protection level: signature
@hide -->
<permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7eca699d9eca..3fef7a2dffae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -433,6 +433,14 @@
-->
</string-array>
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
<!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
<string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastreceiver
</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a8b534061aeb..363bc9ddd75c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -747,6 +747,7 @@
<java-symbol type="string" name="config_default_dns_server" />
<java-symbol type="string" name="config_ethernet_iface_regex" />
<java-symbol type="array" name="config_ethernet_interfaces" />
+ <java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
<java-symbol type="string" name="cellbroadcast_default_package" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f3d68755a513..90e29df45e51 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -145,7 +145,7 @@ public class LocationManager {
* Key used for an extra holding a boolean enabled/disabled status value when a provider
* enabled/disabled event is broadcast using a PendingIntent.
*
- * @see #requestLocationUpdates(String, long, long, PendingIntent)
+ * @see #requestLocationUpdates(String, long, float, PendingIntent)
*/
public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -153,7 +153,7 @@ public class LocationManager {
* Key used for an extra holding a {@link Location} value when a location change is broadcast
* using a PendingIntent.
*
- * @see #requestLocationUpdates(String, long, long, PendingIntent)
+ * @see #requestLocationUpdates(String, long, float, PendingIntent)
*/
public static final String KEY_LOCATION_CHANGED = "location";
@@ -1256,44 +1256,46 @@ public class LocationManager {
}
/**
- * Creates a mock location provider and adds it to the set of active providers.
+ * Creates a test location provider and adds it to the set of active providers. This provider
+ * will replace any provider with the same name that exists prior to this call.
*
- * @param name the provider name
+ * @param provider the provider name
*
+ * @throws IllegalArgumentException if provider is null
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if a provider with the given name already exists
*/
public void addTestProvider(
- @NonNull String name, boolean requiresNetwork, boolean requiresSatellite,
+ @NonNull String provider, boolean requiresNetwork, boolean requiresSatellite,
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
ProviderProperties properties = new ProviderProperties(requiresNetwork,
requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
supportsBearing, powerRequirement, accuracy);
- if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
- throw new IllegalArgumentException("provider name contains illegal character: " + name);
- }
-
try {
- mService.addTestProvider(name, properties, mContext.getOpPackageName());
+ mService.addTestProvider(provider, properties, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Removes the mock location provider with the given name.
+ * Removes the test location provider with the given name or does nothing if no such test
+ * location provider exists.
*
* @param provider the provider name
*
+ * @throws IllegalArgumentException if provider is null
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
*/
public void removeTestProvider(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
try {
mService.removeTestProvider(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1302,60 +1304,53 @@ public class LocationManager {
}
/**
- * Sets a mock location for the given provider.
- * <p>This location will be used in place of any actual location from the provider.
- * The location object must have a minimum number of fields set to be
- * considered a valid LocationProvider Location, as per documentation
- * on {@link Location} class.
+ * Sets a new location for the given test provider. This location will be identiable as a mock
+ * location to all clients via {@link Location#isFromMockProvider()}.
+ *
+ * <p>The location object must have a minimum number of fields set to be considered valid, as
+ * per documentation on {@link Location} class.
*
* @param provider the provider name
- * @param loc the mock location
+ * @param location the mock location
*
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
- * @throws IllegalArgumentException if the location is incomplete
+ * @throws IllegalArgumentException if the provider is null or not a test provider
+ * @throws IllegalArgumentException if the location is null or incomplete
*/
- public void setTestProviderLocation(@NonNull String provider, @NonNull Location loc) {
- if (!loc.isComplete()) {
+ public void setTestProviderLocation(@NonNull String provider, @NonNull Location location) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(location != null, "invalid null location");
+
+ if (!location.isComplete()) {
IllegalArgumentException e = new IllegalArgumentException(
- "Incomplete location object, missing timestamp or accuracy? " + loc);
+ "Incomplete location object, missing timestamp or accuracy? " + location);
if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
- // just log on old platform (for backwards compatibility)
Log.w(TAG, e);
- loc.makeComplete();
+ location.makeComplete();
} else {
- // really throw it!
throw e;
}
}
try {
- mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
+ mService.setTestProviderLocation(provider, location, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Removes any mock location associated with the given provider.
- *
- * @param provider the provider name
+ * Does nothing.
*
- * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
- * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
- * allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
- *
- * @deprecated This function has always been a no-op, and may be removed in the future.
+ * @deprecated This method has always been a no-op, and may be removed in the future.
*/
@Deprecated
public void clearTestProviderLocation(@NonNull String provider) {}
/**
- * Sets a mock enabled value for the given provider. This value will be used in place
- * of any actual value from the provider.
+ * Sets the given test provider to be enabled or disabled.
*
* @param provider the provider name
* @param enabled the mock enabled value
@@ -1363,9 +1358,11 @@ public class LocationManager {
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
+ * @throws IllegalArgumentException if provider is null or not a test provider
*/
public void setTestProviderEnabled(@NonNull String provider, boolean enabled) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
try {
mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
} catch (RemoteException e) {
@@ -1374,14 +1371,8 @@ public class LocationManager {
}
/**
- * Removes any mock enabled value associated with the given provider.
- *
- * @param provider the provider name
- *
- * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
- * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
- * allowed} for your app.
- * @throws IllegalArgumentException if no provider with the given name exists
+ * Equivalent to calling {@link #setTestProviderEnabled(String, boolean)} to disable a test
+ * provider.
*
* @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
*/
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index b69a9d79e5b8..52a03b61d21c 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -53,28 +53,10 @@ public class LocationProvider {
@Deprecated
public static final int AVAILABLE = 2;
- /**
- * A regular expression matching characters that may not appear
- * in the name of a LocationProvider
- * @hide
- */
- public static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]";
-
private final String mName;
private final ProviderProperties mProperties;
- /**
- * Constructs a LocationProvider with the given name. Provider names must
- * consist only of the characters [a-zA-Z0-9].
- *
- * @throws IllegalArgumentException if name contains an illegal character
- *
- * @hide
- */
- public LocationProvider(String name, ProviderProperties properties) {
- if (name.matches(BAD_CHARS_REGEX)) {
- throw new IllegalArgumentException("provider name contains illegal character: " + name);
- }
+ LocationProvider(String name, ProviderProperties properties) {
mName = name;
mProperties = properties;
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 0346010f4587..f421029909bd 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -227,6 +227,44 @@ public class MediaMetadataRetriever implements AutoCloseable {
public native String extractMetadata(int keyCode);
/**
+ * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)}
+ * except that the device will choose the actual {@link Bitmap.Config} to use.
+ *
+ * @param timeUs The time position where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarantee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @param option a hint on how the frame is found. Use
+ * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp earlier than or the same as timeUs. Use
+ * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp later than or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp closest to or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
+ * or may not be a sync frame but is closest to or the same as timeUs.
+ * {@link #OPTION_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at timeUs.
+ *
+ * @return A Bitmap containing a representative video frame, which can be null,
+ * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
+ * be used to query the actual {@link Bitmap.Config}.
+ *
+ * @see {@link #getFrameAtTime(long, int, BitmapParams)}
+ */
+ public Bitmap getFrameAtTime(long timeUs, @Option int option) {
+ if (option < OPTION_PREVIOUS_SYNC ||
+ option > OPTION_CLOSEST) {
+ throw new IllegalArgumentException("Unsupported option: " + option);
+ }
+
+ return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, null);
+ }
+
+ /**
* Call this method after setDataSource(). This method finds a
* representative frame close to the given time position by considering
* the given option if possible, and returns it as a bitmap.
@@ -255,16 +293,60 @@ public class MediaMetadataRetriever implements AutoCloseable {
* {@link #OPTION_CLOSEST} often has larger performance overhead compared
* to the other options if there is no sync frame located at timeUs.
*
+ * @param params BitmapParams that controls the returned bitmap config
+ * (such as pixel formats).
+ *
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
+ *
+ * @see {@link #getFrameAtTime(long, int)}
*/
- public Bitmap getFrameAtTime(long timeUs, @Option int option) {
+ public Bitmap getFrameAtTime(
+ long timeUs, @Option int option, @NonNull BitmapParams params) {
if (option < OPTION_PREVIOUS_SYNC ||
option > OPTION_CLOSEST) {
throw new IllegalArgumentException("Unsupported option: " + option);
}
- return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/);
+ return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, params);
+ }
+
+ /**
+ * This method is similar to {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
+ * except that the device will choose the actual {@link Bitmap.Config} to use.
+ *
+ * @param timeUs The time position in microseconds where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarantee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @param option a hint on how the frame is found. Use
+ * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp earlier than or the same as timeUs. Use
+ * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp later than or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp closest to or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
+ * or may not be a sync frame but is closest to or the same as timeUs.
+ * {@link #OPTION_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at timeUs.
+ *
+ * @param dstWidth expected output bitmap width
+ * @param dstHeight expected output bitmap height
+ * @return A Bitmap containing a representative video frame, which can be null,
+ * if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
+ * be used to query the actual {@link Bitmap.Config}.
+ * @throws IllegalArgumentException if passed in invalid option or width by height
+ * is less than or equal to 0.
+ * @see {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
+ */
+ public Bitmap getScaledFrameAtTime(
+ long timeUs, @Option int option, int dstWidth, int dstHeight) {
+ validate(option, dstWidth, dstHeight);
+ return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
}
/**
@@ -297,15 +379,23 @@ public class MediaMetadataRetriever implements AutoCloseable {
*
* @param dstWidth expected output bitmap width
* @param dstHeight expected output bitmap height
+ * @param params BitmapParams that controls the returned bitmap config
+ * (such as pixel formats).
+ *
* @return A Bitmap of size not larger than dstWidth by dstHeight containing a
* scaled video frame, which can be null, if such a frame cannot be retrieved.
* @throws IllegalArgumentException if passed in invalid option or width by height
* is less than or equal to 0.
+ * @see {@link #getScaledFrameAtTime(long, int, int, int)}
*/
- public Bitmap getScaledFrameAtTime(
- long timeUs, @Option int option, int dstWidth, int dstHeight) {
- if (option < OPTION_PREVIOUS_SYNC ||
- option > OPTION_CLOSEST) {
+ public Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
+ int dstWidth, int dstHeight, @NonNull BitmapParams params) {
+ validate(option, dstWidth, dstHeight);
+ return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
+ }
+
+ private void validate(@Option int option, int dstWidth, int dstHeight) {
+ if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) {
throw new IllegalArgumentException("Unsupported option: " + option);
}
if (dstWidth <= 0) {
@@ -314,8 +404,6 @@ public class MediaMetadataRetriever implements AutoCloseable {
if (dstHeight <= 0) {
throw new IllegalArgumentException("Invalid height: " + dstHeight);
}
-
- return _getFrameAtTime(timeUs, option, dstWidth, dstHeight);
}
/**
@@ -365,10 +453,12 @@ public class MediaMetadataRetriever implements AutoCloseable {
* @see #getFrameAtTime(long, int)
*/
public Bitmap getFrameAtTime() {
- return _getFrameAtTime(-1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/);
+ return _getFrameAtTime(
+ -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null);
}
- private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
+ private native Bitmap _getFrameAtTime(
+ long timeUs, int option, int width, int height, @Nullable BitmapParams params);
public static final class BitmapParams {
private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 18fd1a01cfd6..bc4bcebaf560 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -350,9 +350,10 @@ static jobject getBitmapFromVideoFrame(
return jBitmap;
}
-static int getColorFormat(JNIEnv *env, jobject options) {
+static int getColorFormat(JNIEnv *env, jobject options,
+ int defaultPreferred = HAL_PIXEL_FORMAT_RGBA_8888) {
if (options == NULL) {
- return HAL_PIXEL_FORMAT_RGBA_8888;
+ return defaultPreferred;
}
ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
@@ -383,7 +384,8 @@ static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options
}
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
- JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
+ JNIEnv *env, jobject thiz, jlong timeUs, jint option,
+ jint dst_width, jint dst_height, jobject params)
{
ALOGV("getFrameAtTime: %lld us option: %d dst width: %d heigh: %d",
(long long)timeUs, option, dst_width, dst_height);
@@ -392,10 +394,13 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL;
}
+ // For getFrameAtTime family of calls, default to HAL_PIXEL_FORMAT_RGB_565
+ // to keep the behavior consistent with older releases
+ int colorFormat = getColorFormat(env, params, HAL_PIXEL_FORMAT_RGB_565);
// Call native method to retrieve a video frame
VideoFrame *videoFrame = NULL;
- sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
+ sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option, colorFormat);
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
// Either document why it is safe in this case or address the
@@ -408,7 +413,9 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
return NULL;
}
- return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType);
+ SkColorType outColorType = setOutColorType(env, colorFormat, params);
+
+ return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
}
static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
@@ -739,7 +746,7 @@ static const JNINativeMethod nativeMethods[] = {
(void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",
(void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
- {"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;",
+ {"_getFrameAtTime", "(JIIILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;",
(void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{
"_getImageAtIndex",
diff --git a/mime/Android.bp b/mime/Android.bp
index 8b2b05958b6f..23a8fbf5059c 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -60,7 +60,7 @@ java_genrule {
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-res.jar"],
cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/",
}
@@ -73,42 +73,49 @@ java_genrule {
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-testing-res.jar"],
cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/",
}
-// Combination of all *mime.types resources.
+// Combination of all *mime.types.minimized resources.
filegroup {
- name: "mime.types",
+ name: "mime.types.minimized",
visibility: [
"//visibility:private",
],
srcs: [
- ":debian.mime.types",
- ":android.mime.types",
- ":vendor.mime.types",
+ ":debian.mime.types.minimized",
+ ":android.mime.types.minimized",
+ ":vendor.mime.types.minimized",
],
}
-filegroup {
- name: "android.mime.types",
+java_genrule {
+ name: "android.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["android.mime.types"],
srcs: [
"java-res/android.mime.types",
],
+ // strip comments normalize whitepace drop empty lines
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' > $(out)",
}
-filegroup {
- name: "vendor.mime.types",
+// Unlike the other *mime.types files, vendor.mime.types gets '?' prepended to
+// every field so that its mappings will never overwrite earlier mappings by
+// the other resource files. http://b/141842825
+java_genrule {
+ name: "vendor.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["vendor.mime.types"],
srcs: [
"java-res/vendor.mime.types",
],
+ // strip comments normalize whitepace drop empty lines prepend ? to fields that are missing it
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' | awk '{for(i=1;i<=NF;i++) { sub(/^\\??/, \"?\", $$i); }; print}' > $(out)",
}
diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java
index 03b685df644e..11d20d4d6c80 100644
--- a/mime/java/android/content/type/DefaultMimeMapFactory.java
+++ b/mime/java/android/content/type/DefaultMimeMapFactory.java
@@ -23,11 +23,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
-import java.util.regex.Pattern;
/**
* Creates the framework default {@link MimeMap}, a bidirectional mapping
@@ -53,8 +51,6 @@ public class DefaultMimeMapFactory {
return create(resourceName -> c.getResourceAsStream("/res/" + resourceName));
}
- private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
-
/**
* Creates a {@link MimeMap} instance whose resources are loaded from the
* InputStreams looked up in {@code resourceSupplier}.
@@ -63,33 +59,43 @@ public class DefaultMimeMapFactory {
*/
public static MimeMap create(Function<String, InputStream> resourceSupplier) {
MimeMap.Builder builder = MimeMap.builder();
- parseTypes(builder, true, resourceSupplier, "mime.types");
- parseTypes(builder, true, resourceSupplier, "android.mime.types");
- parseTypes(builder, false, resourceSupplier, "vendor.mime.types");
+ // The files loaded here must be in minimized format with lines of the
+ // form "mime/type ext1 ext2 ext3", i.e. no comments, no empty lines, no
+ // leading/trailing whitespace and with a single space between entries on
+ // each line. See http://b/142267887
+ //
+ // Note: the order here matters - later entries can overwrite earlier ones
+ // (except that vendor.mime.types entries are prefixed with '?' which makes
+ // them never overwrite).
+ parseTypes(builder, resourceSupplier, "debian.mime.types");
+ parseTypes(builder, resourceSupplier, "android.mime.types");
+ parseTypes(builder, resourceSupplier, "vendor.mime.types");
return builder.build();
}
- private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite,
+ private static void parseTypes(MimeMap.Builder builder,
Function<String, InputStream> resourceSupplier, String resourceName) {
try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName));
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
+ List<String> specs = new ArrayList<>(10); // re-use for each line
while ((line = reader.readLine()) != null) {
- int commentPos = line.indexOf('#');
- if (commentPos >= 0) {
- line = line.substring(0, commentPos);
- }
- line = line.trim();
- if (line.isEmpty()) {
- continue;
- }
- List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
- if (!allowOverwrite) {
- // Pretend that the mimeType and each file extension listed in the line
- // carries a "?" prefix, which means that it can add new mappings but
- // not modify existing mappings (putIfAbsent() semantics).
- specs = ensurePrefix("?", specs);
- }
+ specs.clear();
+ // Lines are of the form "mimeSpec extSpec extSpec[...]" with a single space
+ // separating them and no leading/trailing spaces and no empty lines.
+ int startIdx = 0;
+ do {
+ int endIdx = line.indexOf(' ', startIdx);
+ if (endIdx < 0) {
+ endIdx = line.length();
+ }
+ String spec = line.substring(startIdx, endIdx);
+ if (spec.isEmpty()) {
+ throw new IllegalArgumentException("Malformed line: " + line);
+ }
+ specs.add(spec);
+ startIdx = endIdx + 1; // skip over the space
+ } while (startIdx < line.length());
builder.put(specs.get(0), specs.subList(1, specs.size()));
}
} catch (IOException | RuntimeException e) {
@@ -97,15 +103,4 @@ public class DefaultMimeMapFactory {
}
}
- private static List<String> ensurePrefix(String prefix, List<String> strings) {
- List<String> result = new ArrayList<>(strings.size());
- for (String s : strings) {
- if (!s.startsWith(prefix)) {
- s = prefix + s;
- }
- result.add(s);
- }
- return result;
- }
-
}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
index 91b292666756..66be25b53a62 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
@@ -18,9 +18,13 @@ package com.android.server.backup.encryption;
import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/** Utility methods for dealing with Streams */
public class StreamUtils {
+ private static final int MAX_COPY_BUFFER_SIZE = 1024; // 1k copy buffer size.
+
/**
* Close a Closeable and silently ignore any IOExceptions.
*
@@ -33,4 +37,28 @@ public class StreamUtils {
// Silently ignore
}
}
+
+ /**
+ * Copy data from an InputStream to an OutputStream upto a given number of bytes.
+ *
+ * @param in The source InputStream
+ * @param out The destination OutputStream
+ * @param limit The maximum number of bytes to copy
+ * @throws IOException Thrown if there is a problem performing the copy.
+ */
+ public static void copyStream(InputStream in, OutputStream out, int limit) throws IOException {
+ int bufferSize = Math.min(MAX_COPY_BUFFER_SIZE, limit);
+ byte[] buffer = new byte[bufferSize];
+
+ int copied = 0;
+ while (copied < limit) {
+ int maxReadSize = Math.min(bufferSize, limit - copied);
+ int read = in.read(buffer, 0, maxReadSize);
+ if (read < 0) {
+ return; // Reached the stream end before the limit
+ }
+ out.write(buffer, 0, read);
+ copied += read;
+ }
+ }
}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java
new file mode 100644
index 000000000000..0baec8b0a450
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessor.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupTransport;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.backup.encryption.FullBackupDataProcessor;
+import com.android.server.backup.encryption.StreamUtils;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.security.SecureRandom;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+/**
+ * Accepts backup data from a {@link InputStream} and passes it to the encrypted full data backup
+ * path.
+ */
+public class EncryptedFullBackupDataProcessor implements FullBackupDataProcessor {
+
+ private static final String TAG = "EncryptedFullBackupDP";
+
+ private final Context mContext;
+ private final ExecutorService mExecutorService;
+ private final CryptoBackupServer mCryptoBackupServer;
+ private final SecureRandom mSecureRandom;
+ private final RecoverableKeyStoreSecondaryKey mSecondaryKey;
+ private final String mPackageName;
+
+ @Nullable private InputStream mInputStream;
+ @Nullable private PipedOutputStream mOutputStream;
+ @Nullable private EncryptedFullBackupTask mBackupTask;
+ @Nullable private Future<Void> mBackupTaskFuture;
+ @Nullable private FullBackupCallbacks mFullBackupCallbacks;
+
+ public EncryptedFullBackupDataProcessor(
+ Context context,
+ ExecutorService executorService,
+ CryptoBackupServer cryptoBackupServer,
+ SecureRandom secureRandom,
+ RecoverableKeyStoreSecondaryKey secondaryKey,
+ String packageName) {
+ mContext = checkNotNull(context);
+ mExecutorService = checkNotNull(executorService);
+ mCryptoBackupServer = checkNotNull(cryptoBackupServer);
+ mSecureRandom = checkNotNull(secureRandom);
+ mSecondaryKey = checkNotNull(secondaryKey);
+ mPackageName = checkNotNull(packageName);
+ }
+
+ @Override
+ public boolean initiate(InputStream inputStream) throws IOException {
+ checkState(mBackupTask == null, "initiate() twice");
+
+ this.mInputStream = inputStream;
+ mOutputStream = new PipedOutputStream();
+
+ mBackupTask =
+ EncryptedFullBackupTask.newInstance(
+ mContext,
+ mCryptoBackupServer,
+ mSecureRandom,
+ mSecondaryKey,
+ mPackageName,
+ new PipedInputStream(mOutputStream));
+
+ return true;
+ }
+
+ @Override
+ public void start() {
+ checkState(mBackupTask != null, "start() before initiate()");
+ mBackupTaskFuture = mExecutorService.submit(mBackupTask);
+ }
+
+ @Override
+ public int pushData(int numBytes) {
+ checkState(
+ mBackupTaskFuture != null && mInputStream != null && mOutputStream != null,
+ "pushData() before start()");
+
+ // If the upload has failed then stop without pushing any more bytes.
+ if (mBackupTaskFuture.isDone()) {
+ Optional<Exception> exception = getTaskException();
+ Slog.e(TAG, "Encrypted upload failed", exception.orElse(null));
+ if (exception.isPresent()) {
+ reportNetworkFailureIfNecessary(exception.get());
+
+ if (exception.get().getCause() instanceof SizeQuotaExceededException) {
+ return BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+ }
+ }
+
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ try {
+ StreamUtils.copyStream(mInputStream, mOutputStream, numBytes);
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when processing backup", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ @Override
+ public void cancel() {
+ checkState(mBackupTaskFuture != null && mBackupTask != null, "cancel() before start()");
+ mBackupTask.cancel();
+ closeStreams();
+ }
+
+ @Override
+ public int finish() {
+ checkState(mBackupTaskFuture != null, "finish() before start()");
+
+ // getTaskException() waits for the task to finish. We must close the streams first, which
+ // causes the task to finish, otherwise it will block forever.
+ closeStreams();
+ Optional<Exception> exception = getTaskException();
+
+ if (exception.isPresent()) {
+ Slog.e(TAG, "Exception during encrypted full backup", exception.get());
+ reportNetworkFailureIfNecessary(exception.get());
+
+ if (exception.get().getCause() instanceof SizeQuotaExceededException) {
+ return BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+ }
+ return BackupTransport.TRANSPORT_ERROR;
+
+ } else {
+ if (mFullBackupCallbacks != null) {
+ mFullBackupCallbacks.onSuccess();
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+ }
+
+ private void closeStreams() {
+ StreamUtils.closeQuietly(mInputStream);
+ StreamUtils.closeQuietly(mOutputStream);
+ }
+
+ @Override
+ public void handleCheckSizeRejectionZeroBytes() {
+ cancel();
+ }
+
+ @Override
+ public void handleCheckSizeRejectionQuotaExceeded() {
+ cancel();
+ }
+
+ @Override
+ public void handleSendBytesQuotaExceeded() {
+ cancel();
+ }
+
+ @Override
+ public void attachCallbacks(FullBackupCallbacks fullBackupCallbacks) {
+ this.mFullBackupCallbacks = fullBackupCallbacks;
+ }
+
+ private void reportNetworkFailureIfNecessary(Exception exception) {
+ if (!(exception.getCause() instanceof SizeQuotaExceededException)
+ && mFullBackupCallbacks != null) {
+ mFullBackupCallbacks.onTransferFailed();
+ }
+ }
+
+ private Optional<Exception> getTaskException() {
+ if (mBackupTaskFuture != null) {
+ try {
+ mBackupTaskFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ return Optional.of(e);
+ }
+ }
+ return Optional.empty();
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java
new file mode 100644
index 000000000000..a95e87e3a8b7
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/StreamUtilsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@RunWith(RobolectricTestRunner.class)
+public class StreamUtilsTest {
+ private static final int SOURCE_DATA_SIZE = 64;
+
+ private byte[] mSourceData;
+
+ private InputStream mSource;
+ private ByteArrayOutputStream mDestination;
+
+ @Before
+ public void setUp() {
+ mSourceData = new byte[SOURCE_DATA_SIZE];
+ for (byte i = 0; i < SOURCE_DATA_SIZE; i++) {
+ mSourceData[i] = i;
+ }
+ mSource = new ByteArrayInputStream(mSourceData);
+ mDestination = new ByteArrayOutputStream();
+ }
+
+ @Test
+ public void copyStream_copiesAllBytesIfAsked() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length);
+ assertOutputHasBytes(mSourceData.length);
+ }
+
+ @Test
+ public void copyStream_stopsShortIfAsked() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length - 10);
+ assertOutputHasBytes(mSourceData.length - 10);
+ }
+
+ @Test
+ public void copyStream_stopsShortIfAskedToCopyMoreThanAvailable() throws IOException {
+ StreamUtils.copyStream(mSource, mDestination, mSourceData.length + 10);
+ assertOutputHasBytes(mSourceData.length);
+ }
+
+ private void assertOutputHasBytes(int count) {
+ byte[] output = mDestination.toByteArray();
+ assertThat(output.length).isEqualTo(count);
+ for (int i = 0; i < count; i++) {
+ assertThat(output[i]).isEqualTo(mSourceData[i]);
+ }
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java
new file mode 100644
index 000000000000..675d03fb9869
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupDataProcessorTest.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupTransport;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.FullBackupDataProcessor;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.testing.QueuingNonAutomaticExecutorService;
+
+import com.google.common.io.ByteStreams;
+import com.google.common.primitives.Bytes;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+
+import javax.crypto.spec.SecretKeySpec;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(
+ shadows = {
+ EncryptedFullBackupDataProcessorTest.ShadowEncryptedFullBackupTask.class,
+ })
+public class EncryptedFullBackupDataProcessorTest {
+
+ private static final String KEY_GENERATOR_ALGORITHM = "AES";
+
+ private static final String TEST_PACKAGE = "com.example.app1";
+ private static final byte[] TEST_DATA_1 = {1, 2, 3, 4};
+ private static final byte[] TEST_DATA_2 = {5, 6, 7, 8};
+
+ private final RecoverableKeyStoreSecondaryKey mTestSecondaryKey =
+ new RecoverableKeyStoreSecondaryKey(
+ /*alias=*/ "test_key",
+ new SecretKeySpec(
+ new byte[] {
+ 1, 2, 3,
+ },
+ KEY_GENERATOR_ALGORITHM));
+
+ private QueuingNonAutomaticExecutorService mExecutorService;
+ private FullBackupDataProcessor mFullBackupDataProcessor;
+ @Mock private FullBackupDataProcessor.FullBackupCallbacks mFullBackupCallbacks;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mExecutorService = new QueuingNonAutomaticExecutorService();
+ mFullBackupDataProcessor =
+ new EncryptedFullBackupDataProcessor(
+ ApplicationProvider.getApplicationContext(),
+ mExecutorService,
+ mock(CryptoBackupServer.class),
+ new SecureRandom(),
+ mTestSecondaryKey,
+ TEST_PACKAGE);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowEncryptedFullBackupTask.reset();
+ }
+
+ @Test
+ public void initiate_callTwice_throws() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10]));
+
+ assertThrows(
+ IllegalStateException.class,
+ () -> mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10])));
+ }
+
+ @Test
+ public void pushData_writesDataToTask() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ byte[] result = ByteStreams.toByteArray(ShadowEncryptedFullBackupTask.sInputStream);
+ assertThat(result).isEqualTo(Bytes.concat(TEST_DATA_1, TEST_DATA_2));
+ }
+
+ @Test
+ public void pushData_noError_returnsOk() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_OK);
+ }
+
+ @Test
+ public void pushData_ioExceptionOnCopy_returnsError() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+
+ // Close the stream so there's an IO error when the processor tries to write to it.
+ ShadowEncryptedFullBackupTask.sInputStream.close();
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_exceptionDuringUpload_returnsError() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException("Test exception"));
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_quotaExceptionDuringUpload_doesNotLogAndReturnsQuotaExceeded()
+ throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new SizeQuotaExceededException());
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks, never())
+ .onTransferFailed(); // FullBackupSession will handle this.
+ }
+
+ @Test
+ public void pushData_unexpectedEncryptedBackup_logs() throws Exception {
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new GeneralSecurityException());
+ int result = mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void pushData_permanentExceptionDuringUpload_callsErrorCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+ byte[] inputData = Bytes.concat(TEST_DATA_1, TEST_DATA_2);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(inputData));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException());
+ mFullBackupDataProcessor.pushData(TEST_DATA_2.length);
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks).onTransferFailed();
+ }
+
+ @Test
+ public void pushData_beforeInitiate_throws() {
+ assertThrows(
+ IllegalStateException.class,
+ () -> mFullBackupDataProcessor.pushData(/*numBytes=*/ 10));
+ }
+
+ @Test
+ public void cancel_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.cancel();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void cancel_beforeInitiate_throws() {
+ assertThrows(IllegalStateException.class, () -> mFullBackupDataProcessor.cancel());
+ }
+
+ @Test
+ public void finish_noException_returnsTransportOk() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_OK);
+ }
+
+ @Test
+ public void finish_exceptionDuringUpload_returnsTransportError() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException("Test exception"));
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_ERROR);
+ }
+
+ @Test
+ public void finish_successfulBackup_callsSuccessCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTask();
+ mFullBackupDataProcessor.finish();
+
+ verify(mFullBackupCallbacks).onSuccess();
+ verify(mFullBackupCallbacks, never()).onTransferFailed();
+ }
+
+ @Test
+ public void finish_backupFailedWithPermanentError_callsErrorCallback() throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new IOException());
+ mFullBackupDataProcessor.finish();
+
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks).onTransferFailed();
+ }
+
+ @Test
+ public void finish_backupFailedWithQuotaException_doesNotCallbackAndReturnsQuotaExceeded()
+ throws Exception {
+ mFullBackupDataProcessor.attachCallbacks(mFullBackupCallbacks);
+
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ finishBackupTaskWithException(new SizeQuotaExceededException());
+ int result = mFullBackupDataProcessor.finish();
+
+ assertThat(result).isEqualTo(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+ verify(mFullBackupCallbacks, never()).onSuccess();
+ verify(mFullBackupCallbacks, never())
+ .onTransferFailed(); // FullBackupSession will handle this.
+ }
+
+ @Test
+ public void finish_beforeInitiate_throws() {
+ assertThrows(IllegalStateException.class, () -> mFullBackupDataProcessor.finish());
+ }
+
+ @Test
+ public void handleCheckSizeRejectionZeroBytes_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(new byte[10]));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.handleCheckSizeRejectionZeroBytes();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void handleCheckSizeRejectionQuotaExceeded_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.handleCheckSizeRejectionQuotaExceeded();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ @Test
+ public void handleSendBytesQuotaExceeded_cancelsTask() throws Exception {
+ mFullBackupDataProcessor.initiate(new ByteArrayInputStream(TEST_DATA_1));
+ mFullBackupDataProcessor.start();
+ mFullBackupDataProcessor.pushData(TEST_DATA_1.length);
+ mFullBackupDataProcessor.handleSendBytesQuotaExceeded();
+
+ assertThat(ShadowEncryptedFullBackupTask.sCancelled).isTrue();
+ }
+
+ private void finishBackupTask() {
+ mExecutorService.runNext();
+ }
+
+ private void finishBackupTaskWithException(Exception exception) {
+ ShadowEncryptedFullBackupTask.sOnCallException = exception;
+ finishBackupTask();
+ }
+
+ @Implements(EncryptedFullBackupTask.class)
+ public static class ShadowEncryptedFullBackupTask {
+
+ private static InputStream sInputStream;
+ @Nullable private static Exception sOnCallException;
+ private static boolean sCancelled;
+
+ public void __constructor__(
+ ProtoStore<ChunksMetadataProto.ChunkListing> chunkListingStore,
+ TertiaryKeyManager tertiaryKeyManager,
+ EncryptedBackupTask task,
+ InputStream inputStream,
+ String packageName,
+ SecureRandom secureRandom) {
+ sInputStream = inputStream;
+ }
+
+ @Implementation
+ public Void call() throws Exception {
+ if (sOnCallException != null) {
+ throw sOnCallException;
+ }
+
+ return null;
+ }
+
+ @Implementation
+ public void cancel() {
+ sCancelled = true;
+ }
+
+ public static void reset() {
+ sOnCallException = null;
+ sCancelled = false;
+ }
+ }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java
new file mode 100644
index 000000000000..9d2272e29945
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/testing/QueuingNonAutomaticExecutorService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * ExecutorService which needs to be stepped through the jobs in its' queue.
+ *
+ * <p>This is a deliberately simple implementation because it's only used in testing. The queued
+ * jobs are run on the main thread to eliminate any race condition bugs.
+ */
+public class QueuingNonAutomaticExecutorService extends AbstractExecutorService {
+
+ private List<Runnable> mWaitingJobs = new ArrayList<>();
+ private int mWaitingJobCount = 0;
+
+ @Override
+ public void shutdown() {
+ mWaitingJobCount = mWaitingJobs.size();
+ mWaitingJobs = null; // This will force an error if jobs are submitted after shutdown
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ List<Runnable> queuedJobs = mWaitingJobs;
+ shutdown();
+ return queuedJobs;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return mWaitingJobs == null;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return mWaitingJobs == null && mWaitingJobCount == 0;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ long expiry = System.currentTimeMillis() + unit.toMillis(timeout);
+ for (Runnable job : mWaitingJobs) {
+ if (System.currentTimeMillis() > expiry) {
+ return false;
+ }
+
+ job.run();
+ }
+ return true;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ mWaitingJobs.add(command);
+ }
+
+ public void runNext() {
+ if (mWaitingJobs.isEmpty()) {
+ throw new IllegalStateException("Attempted to run jobs on an empty paused executor");
+ }
+
+ mWaitingJobs.remove(0).run();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index c205bb49228c..53a88a9a54e9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -20,6 +20,7 @@ import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -34,8 +35,8 @@ import javax.inject.Singleton;
public class CarNotificationEntryManager extends NotificationEntryManager {
@Inject
- public CarNotificationEntryManager(NotificationData notificationData) {
- super(notificationData);
+ public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
+ super(notificationData, notifLog);
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index cc6e84259893..681d8f543575 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -108,6 +108,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -296,7 +297,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild) {
+ StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild,
+ NotifLog notifLog) {
super(
lightBarController,
autoHideController,
@@ -350,7 +352,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
notificationListener,
configurationController,
statusBarWindowController,
- statusBarWindowViewControllerBuild);
+ statusBarWindowViewControllerBuild,
+ notifLog);
mNavigationBarController = navigationBarController;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index c05c4cdf72d7..de6a3a8840a4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Binder;
import android.os.Build;
@@ -49,7 +48,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -1175,9 +1173,8 @@ final class SettingsState {
}
// If SetupWizard, done.
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- if (packageName.equals(packageManagerInternal.getSetupWizardPackageName())) {
+ String setupWizPackage = context.getPackageManager().getSetupWizardPackageName();
+ if (packageName.equals(setupWizPackage)) {
sSystemUids.put(uid, uid);
return true;
}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index d71d00968162..a0972498ab2a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -381,6 +381,7 @@ public class BugreportProgressService extends Service {
private final class BugreportCallbackImpl extends BugreportCallback {
+ @GuardedBy("mLock")
private final BugreportInfo mInfo;
BugreportCallbackImpl(BugreportInfo info) {
@@ -389,10 +390,12 @@ public class BugreportProgressService extends Service {
@Override
public void onProgress(float progress) {
- if (progress == 0) {
- trackInfoWithId();
+ synchronized (mLock) {
+ if (progress == 0) {
+ trackInfoWithIdLocked();
+ }
+ checkProgressUpdatedLocked(mInfo, (int) progress);
}
- checkProgressUpdated(mInfo, (int) progress);
}
/**
@@ -401,18 +404,21 @@ public class BugreportProgressService extends Service {
*/
@Override
public void onError(@BugreportErrorCode int errorCode) {
- trackInfoWithId();
- stopProgress(mInfo.id);
+ synchronized (mLock) {
+ trackInfoWithIdLocked();
+ stopProgressLocked(mInfo.id);
+ }
Log.e(TAG, "Bugreport API callback onError() errorCode = " + errorCode);
return;
}
@Override
public void onFinished() {
- // TODO: Make all callback functions lock protected.
mInfo.renameBugreportFile();
mInfo.renameScreenshots(mScreenshotsDir);
- sendBugreportFinishedBroadcast();
+ synchronized (mLock) {
+ sendBugreportFinishedBroadcastLocked();
+ }
}
/**
@@ -421,7 +427,8 @@ public class BugreportProgressService extends Service {
* when dumpstate calls one of the callback functions (onProgress, onFinished, onError)
* after the id has been incremented.
*/
- private void trackInfoWithId() {
+ @GuardedBy("mLock")
+ private void trackInfoWithIdLocked() {
final int id = SystemProperties.getInt(PROPERTY_LAST_ID, 1);
if (mBugreportInfos.get(id) == null) {
mInfo.id = id;
@@ -430,74 +437,75 @@ public class BugreportProgressService extends Service {
return;
}
- private void sendBugreportFinishedBroadcast() {
+ @GuardedBy("mLock")
+ private void sendBugreportFinishedBroadcastLocked() {
final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath();
if (mInfo.bugreportFile.length() == 0) {
Log.e(TAG, "Bugreport file empty. File path = " + bugreportFilePath);
return;
}
if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) {
- sendRemoteBugreportFinishedBroadcast(bugreportFilePath, mInfo.bugreportFile);
+ sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath,
+ mInfo.bugreportFile);
} else {
- trackInfoWithId();
+ trackInfoWithIdLocked();
cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE);
final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
intent.putExtra(EXTRA_BUGREPORT, bugreportFilePath);
- addScreenshotToIntent(intent);
+ addScreenshotToIntent(intent, mInfo);
mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
onBugreportFinished(mInfo.id);
}
}
+ }
- private void sendRemoteBugreportFinishedBroadcast(String bugreportFileName,
- File bugreportFile) {
- cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE);
- final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
- final Uri bugreportUri = getUri(mContext, bugreportFile);
- final String bugreportHash = generateFileHash(bugreportFileName);
- if (bugreportHash == null) {
- Log.e(TAG, "Error generating file hash for remote bugreport");
- return;
- }
- intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
- intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
- intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
- android.Manifest.permission.DUMP);
- }
-
- private void addScreenshotToIntent(Intent intent) {
- final File screenshotFile = mInfo.screenshotFiles.isEmpty()
- ? null : mInfo.screenshotFiles.get(0);
- if (screenshotFile != null && screenshotFile.length() > 0) {
- final String screenshotFilePath = screenshotFile.getAbsolutePath();
- intent.putExtra(EXTRA_SCREENSHOT, screenshotFilePath);
- }
- return;
+ private static void sendRemoteBugreportFinishedBroadcast(Context context,
+ String bugreportFileName, File bugreportFile) {
+ cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE);
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
+ final Uri bugreportUri = getUri(context, bugreportFile);
+ final String bugreportHash = generateFileHash(bugreportFileName);
+ if (bugreportHash == null) {
+ Log.e(TAG, "Error generating file hash for remote bugreport");
}
+ intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
+ intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+ intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
+ context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
+ android.Manifest.permission.DUMP);
+ }
- private String generateFileHash(String fileName) {
- String fileHash = null;
- try {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- FileInputStream input = new FileInputStream(new File(fileName));
- byte[] buffer = new byte[65536];
- int size;
- while ((size = input.read(buffer)) > 0) {
- md.update(buffer, 0, size);
- }
- input.close();
- byte[] hashBytes = md.digest();
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < hashBytes.length; i++) {
- sb.append(String.format("%02x", hashBytes[i]));
- }
- fileHash = sb.toString();
- } catch (IOException | NoSuchAlgorithmException e) {
- Log.e(TAG, "generating file hash for bugreport file failed " + fileName, e);
+ private static void addScreenshotToIntent(Intent intent, BugreportInfo info) {
+ final String screenshotFileName = info.name + ".png";
+ final File screenshotFile = new File(BUGREPORT_DIR, screenshotFileName);
+ final String screenshotFilePath = screenshotFile.getAbsolutePath();
+ if (screenshotFile.length() > 0) {
+ intent.putExtra(EXTRA_SCREENSHOT, screenshotFilePath);
+ }
+ return;
+ }
+
+ private static String generateFileHash(String fileName) {
+ String fileHash = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ FileInputStream input = new FileInputStream(new File(fileName));
+ byte[] buffer = new byte[65536];
+ int size;
+ while ((size = input.read(buffer)) > 0) {
+ md.update(buffer, 0, size);
+ }
+ input.close();
+ byte[] hashBytes = md.digest();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < hashBytes.length; i++) {
+ sb.append(String.format("%02x", hashBytes[i]));
}
- return fileHash;
+ fileHash = sb.toString();
+ } catch (IOException | NoSuchAlgorithmException e) {
+ Log.e(TAG, "generating file hash for bugreport file failed " + fileName, e);
}
+ return fileHash;
}
static void cleanupOldFiles(final int minCount, final long minAge) {
@@ -852,7 +860,8 @@ public class BugreportProgressService extends Service {
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
- private void stopProgress(int id) {
+ @GuardedBy("mLock")
+ private void stopProgressLocked(int id) {
if (mBugreportInfos.indexOfKey(id) < 0) {
Log.w(TAG, "ID not watched: " + id);
} else {
@@ -883,7 +892,9 @@ public class BugreportProgressService extends Service {
}
deleteScreenshots(info);
}
- stopProgress(id);
+ synchronized (mLock) {
+ stopProgressLocked(id);
+ }
}
/**
@@ -1178,7 +1189,9 @@ public class BugreportProgressService extends Service {
if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
- stopProgress(info.id);
+ synchronized (mLock) {
+ stopProgressLocked(info.id);
+ }
return;
}
@@ -1290,7 +1303,9 @@ public class BugreportProgressService extends Service {
final Intent sendIntent = buildSendIntent(mContext, info);
if (sendIntent == null) {
Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built");
- stopProgress(id);
+ synchronized (mLock) {
+ stopProgressLocked(id);
+ }
return;
}
@@ -1313,9 +1328,10 @@ public class BugreportProgressService extends Service {
} else {
mContext.startActivity(notifIntent);
}
-
- // ... and stop watching this process.
- stopProgress(id);
+ synchronized (mLock) {
+ // ... and stop watching this process.
+ stopProgressLocked(id);
+ }
}
static void sendShareIntent(Context context, Intent intent) {
@@ -2361,14 +2377,18 @@ public class BugreportProgressService extends Service {
// The right, long-term solution is to provide an onFinished() callback
// on IDumpstateListener and call it instead of using a broadcast.
Log.w(TAG, "Dumpstate process died:\n" + info);
- stopProgress(info.id);
+ synchronized (mLock) {
+ stopProgressLocked(info.id);
+ }
}
token.asBinder().unlinkToDeath(this, 0);
}
@Override
public void onProgress(int progress) throws RemoteException {
- checkProgressUpdated(info, progress);
+ synchronized (mLock) {
+ checkProgressUpdatedLocked(info, progress);
+ }
}
@Override
@@ -2387,7 +2407,8 @@ public class BugreportProgressService extends Service {
}
- private void checkProgressUpdated(BugreportInfo info, int progress) {
+ @GuardedBy("mLock")
+ private void checkProgressUpdatedLocked(BugreportInfo info, int progress) {
if (progress > CAPPED_PROGRESS) {
progress = CAPPED_PROGRESS;
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 403e894a68e4..b288eb7b5070 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -243,6 +243,9 @@
<!-- Permission to change the display color -->
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <!-- Query all packages on device on R+ -->
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
index f9ffb804f9f3..5010f319f8b4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java
@@ -43,6 +43,7 @@ public class AssistHandleViewController implements NavigationBarTransitions.Dark
private Handler mHandler;
private CornerHandleView mAssistHintLeft;
private CornerHandleView mAssistHintRight;
+ private int mBottomOffset;
@VisibleForTesting
boolean mAssistHintVisible;
@@ -62,6 +63,23 @@ public class AssistHandleViewController implements NavigationBarTransitions.Dark
}
/**
+ * Set the bottom offset.
+ *
+ * @param bottomOffset the bottom offset to translate.
+ */
+ public void setBottomOffset(int bottomOffset) {
+ if (mBottomOffset != bottomOffset) {
+ mBottomOffset = bottomOffset;
+ if (mAssistHintVisible) {
+ // If assist handles are visible, hide them without animation and then make them
+ // show once again (with corrected bottom offset).
+ hideAssistHandles();
+ setAssistHintVisible(true);
+ }
+ }
+ }
+
+ /**
* Controls the visibility of the assist gesture handles.
*
* @param visible whether the handles should be shown
@@ -126,7 +144,8 @@ public class AssistHandleViewController implements NavigationBarTransitions.Dark
xDirection * translationStart * view.getWidth(),
xDirection * translationEnd * view.getWidth());
Animator translateY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
- translationStart * view.getHeight(), translationEnd * view.getHeight());
+ translationStart * view.getHeight() + mBottomOffset,
+ translationEnd * view.getHeight() + mBottomOffset);
AnimatorSet set = new AnimatorSet();
set.play(scaleX).with(scaleY);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 824034507019..cc548d0c7f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -569,7 +569,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (mStackView != null) {
mStackView.updateDotVisibility(entry.key);
}
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleController.onNotificationRemoveRequested");
return true;
} else if (!userRemovedNotif && entry != null) {
// This wasn't a user removal so we should remove the bubble as well
@@ -609,7 +610,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleData.addSummaryToSuppress(summary.notification.getGroupKey(),
summary.key);
// Tell shade to update for the suppression
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleController.handleSummaryRemovalInterception");
}
return !isAutogroupSummary;
} else {
@@ -760,7 +762,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mStackView.setExpanded(true);
}
- mNotificationEntryManager.updateNotifications();
+ mNotificationEntryManager.updateNotifications(
+ "BubbleData.Listener.applyUpdate");
updateStack();
if (DEBUG_BUBBLE_CONTROLLER) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 6c0f90a65ae9..c4de2d3572bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -127,7 +127,7 @@ public class NotificationListener extends NotificationListenerWithPlugins {
mEntryManager.removeNotification(key, rankingMap, UNDEFINED_DISMISS_REASON);
} else {
mEntryManager.getNotificationData()
- .updateRanking(rankingMap);
+ .updateRanking(rankingMap, "onNotificationPosted");
}
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4ba111436048..6ffea79c420a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -106,7 +106,7 @@ public class NotificationLockscreenUserManagerImpl implements
isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
}
}
};
@@ -124,7 +124,7 @@ public class NotificationLockscreenUserManagerImpl implements
updatePublicMode();
// The filtering needs to happen before the update call below in order to make sure
// the presenter has the updated notifications from the new user
- getEntryManager().getNotificationData().filterAndSort();
+ getEntryManager().getNotificationData().filterAndSort("user switched");
mPresenter.onUserSwitched(mCurrentUserId);
for (UserChangedListener listener : mListeners) {
@@ -205,7 +205,8 @@ public class NotificationLockscreenUserManagerImpl implements
mUsersAllowingNotifications.clear();
// ... and refresh all the notifications
updateLockscreenNotificationSetting();
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
+ + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
}
};
@@ -214,7 +215,8 @@ public class NotificationLockscreenUserManagerImpl implements
public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting();
if (mDeviceProvisionedController.isDeviceProvisioned()) {
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
+ + " or ZEN_MODE change");
}
}
};
@@ -532,7 +534,7 @@ public class NotificationLockscreenUserManagerImpl implements
setLockscreenPublicMode(isProfilePublic, userId);
mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
}
- getEntryManager().updateNotifications();
+ getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index c50fb3d76b51..3616b541741c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -361,7 +361,7 @@ public class NotificationMediaManager implements Dumpable {
}
if (metaDataChanged) {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
}
dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 148a1a87f305..01c79b3df064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -40,6 +40,8 @@ import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
@@ -92,6 +94,7 @@ public class NotificationEntryManager implements
private NotificationListenerService.RankingMap mLatestRankingMap;
@VisibleForTesting
protected NotificationData mNotificationData;
+ private NotifLog mNotifLog;
@VisibleForTesting
final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
@@ -123,8 +126,9 @@ public class NotificationEntryManager implements
}
@Inject
- public NotificationEntryManager(NotificationData notificationData) {
+ public NotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
mNotificationData = notificationData;
+ mNotifLog = notifLog;
}
/** Adds a {@link NotificationEntryListener}. */
@@ -178,7 +182,7 @@ public class NotificationEntryManager implements
@Override
public void onReorderingAllowed() {
- updateNotifications();
+ updateNotifications("reordering is now allowed");
}
/**
@@ -203,15 +207,19 @@ public class NotificationEntryManager implements
return NotificationVisibility.obtain(key, rank, count, true, location);
}
- private void abortExistingInflation(String key) {
+ private void abortExistingInflation(String key, String reason) {
if (mPendingNotifications.containsKey(key)) {
NotificationEntry entry = mPendingNotifications.get(key);
entry.abortTask();
mPendingNotifications.remove(key);
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.sbn(), null,
+ "PendingNotification aborted. " + reason);
}
NotificationEntry addedEntry = mNotificationData.get(key);
if (addedEntry != null) {
addedEntry.abortTask();
+ mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.sbn(),
+ null, reason);
}
}
@@ -247,7 +255,7 @@ public class NotificationEntryManager implements
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onBeforeNotificationAdded(entry);
}
- updateNotifications();
+ updateNotifications("onAsyncInflationFinished");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationAdded(entry);
}
@@ -276,7 +284,8 @@ public class NotificationEntryManager implements
if (mRemoveInterceptor != null
&& mRemoveInterceptor.onNotificationRemoveRequested(key, reason)) {
- // Remove intercepted; skip
+ // Remove intercepted; log and skip
+ mNotifLog.log(NotifEvent.REMOVE_INTERCEPTED);
return;
}
@@ -291,13 +300,17 @@ public class NotificationEntryManager implements
if (extender.shouldExtendLifetimeForPendingNotification(pendingEntry)) {
extendLifetime(pendingEntry, extender);
lifetimeExtended = true;
+ mNotifLog.log(
+ NotifEvent.LIFETIME_EXTENDED,
+ pendingEntry.sbn(),
+ "pendingEntry extendedBy=" + extender.toString());
}
}
}
}
if (!lifetimeExtended) {
- abortExistingInflation(key);
+ abortExistingInflation(key, "removeNotification");
}
if (entry != null) {
@@ -310,6 +323,10 @@ public class NotificationEntryManager implements
mLatestRankingMap = ranking;
extendLifetime(entry, extender);
lifetimeExtended = true;
+ mNotifLog.log(
+ NotifEvent.LIFETIME_EXTENDED,
+ entry.sbn(),
+ "entry extendedBy=" + extender.toString());
break;
}
}
@@ -329,10 +346,12 @@ public class NotificationEntryManager implements
handleGroupSummaryRemoved(key);
mNotificationData.remove(key, ranking);
- updateNotifications();
+ updateNotifications("removeNotificationInternal");
Dependency.get(LeakDetector.class).trackGarbage(entry);
removedByUser |= entryDismissed;
+ mNotifLog.log(NotifEvent.NOTIF_REMOVED, entry.sbn(),
+ "removedByUser=" + removedByUser);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryRemoved(entry, visibility, removedByUser);
}
@@ -389,7 +408,7 @@ public class NotificationEntryManager implements
Log.d(TAG, "addNotification key=" + key);
}
- mNotificationData.updateRanking(rankingMap);
+ mNotificationData.updateRanking(rankingMap, "addNotificationInternal");
Ranking ranking = new Ranking();
rankingMap.getRanking(key, ranking);
@@ -400,9 +419,9 @@ public class NotificationEntryManager implements
requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
REASON_CANCEL));
- abortExistingInflation(key);
-
+ abortExistingInflation(key, "addNotification");
mPendingNotifications.put(key, entry);
+ mNotifLog.log(NotifEvent.NOTIF_ADDED, entry.sbn());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPendingEntryAdded(entry);
}
@@ -423,7 +442,7 @@ public class NotificationEntryManager implements
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
- abortExistingInflation(key);
+ abortExistingInflation(key, "updateNotification");
NotificationEntry entry = mNotificationData.get(key);
if (entry == null) {
return;
@@ -433,15 +452,15 @@ public class NotificationEntryManager implements
// to keep its lifetime extended.
cancelLifetimeExtension(entry);
- mNotificationData.update(entry, ranking, notification);
-
+ mNotificationData.update(entry, ranking, notification, "updateNotificationInternal");
+ mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.sbn(), entry.ranking());
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
requireBinder().inflateViews(entry, () -> performRemoveNotification(notification,
REASON_CANCEL));
- updateNotifications();
+ updateNotifications("updateNotificationInternal");
if (DEBUG) {
// Is this for you?
@@ -465,8 +484,12 @@ public class NotificationEntryManager implements
}
}
- public void updateNotifications() {
- mNotificationData.filterAndSort();
+ /**
+ * Update the notifications
+ * @param reason why the notifications are updating
+ */
+ public void updateNotifications(String reason) {
+ mNotificationData.filterAndSort(reason);
if (mPresenter != null) {
mPresenter.updateNotificationViews();
}
@@ -489,7 +512,7 @@ public class NotificationEntryManager implements
}
// Populate notification entries from the new rankings.
- mNotificationData.updateRanking(rankingMap);
+ mNotificationData.updateRanking(rankingMap, "updateNotificationRanking");
updateRankingOfPendingNotifications(rankingMap);
// By comparing the old and new UI adjustments, reinflate the view accordingly.
@@ -501,7 +524,7 @@ public class NotificationEntryManager implements
NotificationUiAdjustment.extractFromNotificationEntry(entry));
}
- updateNotifications();
+ updateNotifications("updateNotificationRanking");
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onNotificationRankingUpdated(rankingMap);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 769cbb7b984c..970cbf9aa1e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -81,7 +81,7 @@ public class NotificationListController {
new DeviceProvisionedListener() {
@Override
public void onDeviceProvisionedChanged() {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("device provisioned changed");
}
};
@@ -106,7 +106,7 @@ public class NotificationListController {
if (foregroundKey != null) {
mEntryManager
.getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("app opp changed pkg=" + pkg);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index cf0fbbb5d9c1..a98fa664a357 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -35,6 +35,8 @@ import com.android.systemui.Dependency;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -73,10 +75,13 @@ public class NotificationData {
private RankingMap mRankingMap;
private final Ranking mTmpRanking = new Ranking();
private final boolean mUsePeopleFiltering;
+ private final NotifLog mNotifLog;
@Inject
- public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
+ public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager,
+ NotifLog notifLog) {
mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
+ mNotifLog = notifLog;
}
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -179,7 +184,7 @@ public class NotificationData {
}
mGroupManager.onEntryAdded(entry);
- updateRankingAndSort(mRankingMap);
+ updateRankingAndSort(mRankingMap, "addEntry=" + entry.sbn());
}
public NotificationEntry remove(String key, RankingMap ranking) {
@@ -189,7 +194,7 @@ public class NotificationData {
}
if (removed == null) return null;
mGroupManager.onEntryRemoved(removed);
- updateRankingAndSort(ranking);
+ updateRankingAndSort(ranking, "removeEntry=" + removed.sbn());
return removed;
}
@@ -197,15 +202,19 @@ public class NotificationData {
public void update(
NotificationEntry entry,
RankingMap ranking,
- StatusBarNotification notification) {
- updateRanking(ranking);
+ StatusBarNotification notification,
+ String reason) {
+ updateRanking(ranking, reason);
final StatusBarNotification oldNotification = entry.notification;
entry.setNotification(notification);
mGroupManager.onEntryUpdated(entry, oldNotification);
}
- public void updateRanking(RankingMap ranking) {
- updateRankingAndSort(ranking);
+ /**
+ * Update ranking and trigger a re-sort
+ */
+ public void updateRanking(RankingMap ranking, String reason) {
+ updateRankingAndSort(ranking, reason);
}
public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
@@ -352,7 +361,7 @@ public class NotificationData {
return false;
}
- private void updateRankingAndSort(RankingMap rankingMap) {
+ private void updateRankingAndSort(RankingMap rankingMap, String reason) {
if (rankingMap != null) {
mRankingMap = rankingMap;
synchronized (mEntries) {
@@ -375,7 +384,7 @@ public class NotificationData {
}
}
}
- filterAndSort();
+ filterAndSort(reason);
}
/**
@@ -393,7 +402,11 @@ public class NotificationData {
// TODO: This should not be public. Instead the Environment should notify this class when
// anything changed, and this class should call back the UI so it updates itself.
- public void filterAndSort() {
+ /**
+ * Filters and sorts the list of notification entries
+ */
+ public void filterAndSort(String reason) {
+ mNotifLog.log(NotifEvent.FILTER_AND_SORT, reason);
mSortedAndFiltered.clear();
synchronized (mEntries) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 60cf995ad8d1..e5571b64cc9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -41,6 +41,8 @@ import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.logging.NotifEvent;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
@@ -72,6 +74,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private final boolean mAllowLongPress;
private final KeyguardBypassController mKeyguardBypassController;
private final StatusBarStateController mStatusBarStateController;
+ private final NotifLog mNotifLog;
private NotificationRemoteInputManager mRemoteInputManager;
private NotificationPresenter mPresenter;
@@ -85,12 +88,14 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
public NotificationRowBinderImpl(Context context, boolean allowLongPress,
KeyguardBypassController keyguardBypassController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ NotifLog notifLog) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mNotifLog = notifLog;
}
private NotificationRemoteInputManager getRemoteInputManager() {
@@ -143,6 +148,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
row -> {
bindRow(entry, pmUser, sbn, row, onDismissRunnable);
updateNotification(entry, pmUser, sbn, row);
+ mNotifLog.log(NotifEvent.INFLATED, sbn);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 2396d28bd46d..7703cbd94e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -30,9 +30,9 @@ import java.lang.annotation.RetentionPolicy;
* and triaging purposes.
*/
public class NotifEvent extends RichEvent {
- public static final int TOTAL_EVENT_TYPES = 8;
- private StatusBarNotification mSbn;
- private Ranking mRanking;
+ public static final int TOTAL_EVENT_TYPES = 11;
+ private final StatusBarNotification mSbn;
+ private final Ranking mRanking;
/**
* Creates a NotifEvent with an event type that matches with an index in the array
@@ -44,9 +44,20 @@ public class NotifEvent extends RichEvent {
public NotifEvent(int logLevel, int type, String reason, StatusBarNotification sbn,
Ranking ranking) {
super(logLevel, type, reason);
- mSbn = sbn.clone();
- mRanking = new Ranking();
- mRanking.populate(ranking);
+
+ if (sbn != null) {
+ mSbn = sbn.cloneLight();
+ } else {
+ mSbn = null;
+ }
+
+ if (ranking != null) {
+ mRanking = new Ranking();
+ mRanking.populate(ranking);
+ } else {
+ mRanking = null;
+ }
+
mMessage += getExtraInfo();
}
@@ -76,11 +87,14 @@ public class NotifEvent extends RichEvent {
"NotifAdded",
"NotifRemoved",
"NotifUpdated",
- "HeadsUpStarted",
- "HeadsUpEnded",
"Filter",
"Sort",
+ "FilterAndSort",
"NotifVisibilityChanged",
+ "LifetimeExtended",
+ "RemoveIntercepted",
+ "InflationAborted",
+ "Inflated"
};
if (events.length != TOTAL_EVENT_TYPES) {
@@ -135,8 +149,19 @@ public class NotifEvent extends RichEvent {
}
}
- @IntDef({NOTIF_ADDED, NOTIF_REMOVED, NOTIF_UPDATED, HEADS_UP_STARTED, HEADS_UP_ENDED, FILTER,
- SORT, NOTIF_VISIBILITY_CHANGED})
+ @IntDef({NOTIF_ADDED,
+ NOTIF_REMOVED,
+ NOTIF_UPDATED,
+ FILTER,
+ SORT,
+ FILTER_AND_SORT,
+ NOTIF_VISIBILITY_CHANGED,
+ LIFETIME_EXTENDED,
+ REMOVE_INTERCEPTED,
+ INFLATION_ABORTED,
+ INFLATED
+ })
+
/**
* Types of NotifEvents
*/
@@ -145,9 +170,13 @@ public class NotifEvent extends RichEvent {
public static final int NOTIF_ADDED = 0;
public static final int NOTIF_REMOVED = 1;
public static final int NOTIF_UPDATED = 2;
- public static final int HEADS_UP_STARTED = 3;
- public static final int HEADS_UP_ENDED = 4;
- public static final int FILTER = 5;
- public static final int SORT = 6;
- public static final int NOTIF_VISIBILITY_CHANGED = 7;
+ public static final int FILTER = 3;
+ public static final int SORT = 4;
+ public static final int FILTER_AND_SORT = 5;
+ public static final int NOTIF_VISIBILITY_CHANGED = 6;
+ public static final int LIFETIME_EXTENDED = 7;
+ // unable to remove notif - removal intercepted by {@link NotificationRemoveInterceptor}
+ public static final int REMOVE_INTERCEPTED = 8;
+ public static final int INFLATION_ABORTED = 9;
+ public static final int INFLATED = 10;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
index d42cd82f9784..8466d2e83002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
@@ -82,6 +82,14 @@ public class NotifLog extends SysuiLog {
}
/**
+ * Logs a {@link NotifEvent} with a notification
+ * @return true if successfully logged, else false
+ */
+ public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn, String msg) {
+ return log(eventType, sbn, null, msg);
+ }
+
+ /**
* Logs a {@link NotifEvent} with a ranking
* @return true if successfully logged, else false
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9f4b026b3d38..924a3470b832 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1447,6 +1447,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
setDismissed(fromAccessibility);
if (mEntry.isClearable()) {
+ // TODO: beverlyt, log dismissal
// TODO: track dismiss sentiment
if (mOnDismissRunnable != null) {
mOnDismissRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
index 73093c6f471f..37f63c9779f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
@@ -139,7 +139,8 @@ public class NotificationBlockingHelperManager {
mBlockingHelperRow.setBlockingHelperShowing(false);
if (mBlockingHelperRow.isAttachedToWindow()) {
- Dependency.get(NotificationEntryManager.class).updateNotifications();
+ Dependency.get(NotificationEntryManager.class).updateNotifications(
+ "dismissCurrentBlockingHelper");
}
mBlockingHelperRow = null;
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f5705c5f643b..7bbe8188b402 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5333,7 +5333,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
requestChildrenUpdate();
onUpdateRowStates();
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("StatusBar state changed");
updateVisibility();
}
@@ -6492,12 +6492,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
- mStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren");
}
@Override
public void onGroupsChanged() {
- mStatusBar.requestNotificationUpdate();
+ mStatusBar.requestNotificationUpdate("onGroupsChanged");
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index a1a47e1305f5..2aae5b1b9139 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -67,6 +67,7 @@ import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.assist.AssistHandleViewController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
@@ -75,6 +76,7 @@ import com.android.systemui.recents.RecentsOnboarding;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -1198,6 +1200,19 @@ public class NavigationBarView extends FrameLayout implements
// we're passing the insets onto the gesture handler since the back arrow is only
// conditionally added and doesn't always get all the insets.
mEdgeBackGestureHandler.setInsets(leftInset, rightInset);
+
+ // this allows assist handle to be drawn outside its bound so that it can align screen
+ // bottom by translating its y position.
+ final boolean shouldClip =
+ !isGesturalMode(mNavBarMode) || insets.getSystemWindowInsetBottom() == 0;
+ setClipChildren(shouldClip);
+ setClipToPadding(shouldClip);
+
+ AssistHandleViewController controller = Dependency.get(NavigationBarController.class)
+ .getAssistHandlerViewController();
+ if (controller != null) {
+ controller.setBottomOffset(insets.getSystemWindowInsetBottom());
+ }
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 6ce6dfaf3c20..2b80d2282661 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -210,6 +210,7 @@ import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -385,6 +386,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
private final StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
+ private final NotifLog mNotifLog;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -585,7 +587,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onStrongAuthStateChanged(int userId) {
super.onStrongAuthStateChanged(userId);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onStrongAuthStateChanged");
}
};
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -599,6 +601,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mPulsing;
private final BubbleController mBubbleController;
private final BubbleController.BubbleExpandListener mBubbleExpandListener;
+
private ActivityIntentHelper mActivityIntentHelper;
@Override
@@ -669,7 +672,8 @@ public class StatusBar extends SystemUI implements DemoMode,
NotificationListener notificationListener,
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
- StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder) {
+ StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+ NotifLog notifLog) {
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -723,10 +727,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mConfigurationController = configurationController;
mStatusBarWindowController = statusBarWindowController;
mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder;
+ mNotifLog = notifLog;
mBubbleExpandListener =
(isExpanding, key) -> {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onBubbleExpandChanged");
updateScrimController();
};
}
@@ -1160,7 +1165,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mContext,
mAllowNotificationLongPress,
mKeyguardBypassController,
- mStatusBarStateController);
+ mStatusBarStateController,
+ mNotifLog);
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
@@ -1443,8 +1449,12 @@ public class StatusBar extends SystemUI implements DemoMode,
return mZenController.areNotificationsHiddenInShade();
}
- public void requestNotificationUpdate() {
- mEntryManager.updateNotifications();
+ /**
+ * Request a notification update
+ * @param reason why we're requesting a notification update
+ */
+ public void requestNotificationUpdate(String reason) {
+ mEntryManager.updateNotifications(reason);
}
/**
@@ -1685,7 +1695,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onHeadsUpStateChanged");
if (isDozing() && isHeadsUp) {
entry.setPulseSuppressed(false);
mDozeServiceHost.fireNotificationPulse(entry);
@@ -3566,7 +3576,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
- mEntryManager.updateNotifications();
+ mEntryManager.updateNotifications("onDozingChanged");
updateDozingState();
updateScrimController();
updateReportRejectedTouchVisibility();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 2798c6b56771..5a2b5e38222a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -33,6 +33,7 @@ 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.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -91,7 +92,6 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class BubbleControllerTest extends SysuiTestCase {
-
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
@@ -223,13 +223,13 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.updateBubble(mRow.getEntry());
assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
assertTrue(mBubbleController.hasBubbles());
- verify(mNotificationEntryManager).updateNotifications();
+ verify(mNotificationEntryManager).updateNotifications(any());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
assertFalse(mStatusBarWindowController.getBubblesShowing());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
- verify(mNotificationEntryManager, times(2)).updateNotifications();
+ verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
}
@@ -257,16 +257,16 @@ public class BubbleControllerTest extends SysuiTestCase {
@Test
public void testDismissStack() {
mBubbleController.updateBubble(mRow.getEntry());
- verify(mNotificationEntryManager, times(1)).updateNotifications();
+ verify(mNotificationEntryManager, times(1)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
mBubbleController.updateBubble(mRow2.getEntry());
- verify(mNotificationEntryManager, times(2)).updateNotifications();
+ verify(mNotificationEntryManager, times(2)).updateNotifications(any());
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().key));
assertTrue(mBubbleController.hasBubbles());
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
assertFalse(mStatusBarWindowController.getBubblesShowing());
- verify(mNotificationEntryManager, times(3)).updateNotifications();
+ verify(mNotificationEntryManager, times(3)).updateNotifications(any());
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().key));
assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().key));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index a02764320b6c..0569c55981fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -25,6 +25,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -99,7 +100,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
@Test
public void testLockScreenShowNotificationsChangeUpdatesNotifications() {
mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications();
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
@@ -138,7 +139,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
public void testSettingsObserverUpdatesNotifications() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
mLockscreenUserManager.getSettingsObserverForTest().onChange(false);
- verify(mEntryManager, times(1)).updateNotifications();
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 866ea5112794..e52a25806086 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -28,6 +28,7 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -80,6 +81,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationData.K
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -146,7 +148,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
private final CountDownLatch mCountDownLatch;
TestableNotificationEntryManager() {
- super(new NotificationData(mock(NotificationSectionsFeatureManager.class)));
+ super(new NotificationData(mock(NotificationSectionsFeatureManager.class),
+ mock(NotifLog.class)), mock(NotifLog.class));
mCountDownLatch = new CountDownLatch(1);
}
@@ -259,7 +262,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
NotificationRowBinderImpl notificationRowBinder =
new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
- mock(KeyguardBypassController.class), mock(StatusBarStateController.class));
+ mock(KeyguardBypassController.class),
+ mock(StatusBarStateController.class),
+ mock(NotifLog.class));
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
@@ -350,7 +355,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
// Ensure that update callbacks happen in correct order
InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener);
order.verify(mEntryListener).onPreEntryUpdated(mEntry);
- order.verify(notifData).filterAndSort();
+ order.verify(notifData).filterAndSort(anyString());
order.verify(mPresenter).updateNotificationViews();
order.verify(mEntryListener).onPostEntryUpdated(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index 6d275419ee94..8207a041ef50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -21,6 +21,7 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -43,6 +44,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -76,7 +78,7 @@ public class NotificationListControllerTest extends SysuiTestCase {
// TODO: Remove this once EntryManager no longer needs to be mocked
private NotificationData mNotificationData =
new NotificationData(new NotificationSectionsFeatureManager(
- new DeviceConfigProxyFake(), mContext));
+ new DeviceConfigProxyFake(), mContext), mock(NotifLog.class));
private int mNextNotifId = 0;
@@ -113,7 +115,7 @@ public class NotificationListControllerTest extends SysuiTestCase {
@Test
public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
mProvisionedListener.onDeviceProvisionedChanged();
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
@@ -133,8 +135,8 @@ public class NotificationListControllerTest extends SysuiTestCase {
// THEN the app op is added to the entry
assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
- // THEN updateNotifications() is called
- verify(mEntryManager, times(1)).updateNotifications();
+ // THEN updateNotifications(TEST) is called
+ verify(mEntryManager, times(1)).updateNotifications(anyString());
}
@Test
@@ -146,8 +148,8 @@ public class NotificationListControllerTest extends SysuiTestCase {
// WHEN An unrelated notification gets a new app op
mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
- // THEN We never call updateNotifications()
- verify(mEntryManager, never()).updateNotifications();
+ // THEN We never call updateNotifications(TEST)
+ verify(mEntryManager, never()).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 5fbacb1d7adf..59c76a8cbb77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -79,6 +79,7 @@ import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -141,7 +142,7 @@ public class NotificationDataTest extends SysuiTestCase {
when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
mNotificationData = new TestableNotificationData(
mock(NotificationSectionsFeatureManager.class));
- mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
+ mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class), "");
mRow = new NotificationTestHelper(getContext()).createRow();
Dependency.get(InitController.class).executePostInitTasks();
}
@@ -633,7 +634,7 @@ public class NotificationDataTest extends SysuiTestCase {
public static class TestableNotificationData extends NotificationData {
public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
- super(sectionsFeatureManager);
+ super(sectionsFeatureManager, mock(NotifLog.class));
}
public static final String OVERRIDE_RANK = "r";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
index 6d6439532912..cc89504cb54d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -62,7 +63,6 @@ import org.mockito.MockitoAnnotations;
@org.junit.runner.RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
-
private NotificationBlockingHelperManager mBlockingHelperManager;
private NotificationTestHelper mHelper;
@@ -112,7 +112,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager, times(0)).updateNotifications();
+ verify(mEntryManager, times(0)).updateNotifications(anyString());
}
@Test
@@ -125,7 +125,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
@@ -267,7 +267,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
- verify(mEntryManager).updateNotifications();
+ verify(mEntryManager).updateNotifications(anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 98485b311d17..95e9e67cb830 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -56,6 +56,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -232,7 +233,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mock(ShadeController.class),
mock(NotificationLockscreenUserManager.class),
new NotificationEntryManager(new NotificationData(mock(
- NotificationSectionsFeatureManager.class))),
+ NotificationSectionsFeatureManager.class), mock(NotifLog.class)),
+ mock(NotifLog.class)),
mock(DozeLog.class));
mNotificationStackScroller = mNotificationStackScrollLayout;
mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 914717c0266d..12e9be15354f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -117,6 +117,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -218,6 +219,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
@Mock private StatusBarWindowViewController mStatusBarWindowViewController;
+ @Mock private NotifLog mNotifLog;
@Before
public void setup() throws Exception {
@@ -339,7 +341,8 @@ public class StatusBarTest extends SysuiTestCase {
mNotificationListener,
configurationController,
mStatusBarWindowController,
- mStatusBarWindowViewControllerBuilder);
+ mStatusBarWindowViewControllerBuilder,
+ mNotifLog);
// TODO: we should be able to call mStatusBar.start() and have all the below values
// initialized automatically.
mStatusBar.mContext = mContext;
@@ -873,7 +876,7 @@ public class StatusBarTest extends SysuiTestCase {
public static class TestableNotificationEntryManager extends NotificationEntryManager {
public TestableNotificationEntryManager(NotificationData notificationData) {
- super(notificationData);
+ super(notificationData, mock(NotifLog.class));
}
public void setUpForTest(NotificationPresenter presenter,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 3eef92fc0aa7..1d666adff561 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -33,6 +33,8 @@ import android.os.PersistableBundle;
import android.util.ArraySet;
import android.util.SparseArray;
+import com.android.server.pm.PackageList;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b158c32cb7b2..e0f60b43f8c8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -579,6 +579,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the set of network types that can only be enabled by system/sig apps
private List mProtectedNetworks;
+ private Set<String> mWolSupportedInterfaces;
+
private TelephonyManager mTelephonyManager;
private KeepaliveTracker mKeepaliveTracker;
@@ -1055,6 +1057,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ mWolSupportedInterfaces = new ArraySet(
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces));
+
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
@@ -5600,6 +5606,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
updateProxy(newLp, oldLp);
}
+
+ updateWakeOnLan(newLp);
+
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) {
@@ -5770,6 +5779,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
+ }
+
private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
return INetd.PERMISSION_SYSTEM;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 35a06a977a58..09f62ff3fc56 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -3064,11 +3064,6 @@ public class LocationManagerService extends ILocationManager.Stub {
try {
LocationProvider oldProvider = getLocationProviderLocked(name);
if (oldProvider != null) {
- if (oldProvider.isMock()) {
- throw new IllegalArgumentException(
- "Provider \"" + name + "\" already exists");
- }
-
removeProviderLocked(oldProvider);
}
@@ -3093,7 +3088,7 @@ public class LocationManagerService extends ILocationManager.Stub {
try {
LocationProvider testProvider = getLocationProviderLocked(name);
if (testProvider == null || !testProvider.isMock()) {
- throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
+ return;
}
removeProviderLocked(testProvider);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7cbd1fcebb94..a450479cfc97 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18353,7 +18353,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int getCurrentUserId() {
- return mUserController.getCurrentUserIdLU();
+ return mUserController.getCurrentUserId();
}
@Override
diff --git a/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java b/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java
new file mode 100644
index 000000000000..dc30dc39f44a
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/EvaluationOutcome.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.model;
+
+/**
+ * A class encapsulating the result from the evaluation engine after evaluating rules against app
+ * install metadata.
+ *
+ * <p>It contains the outcome effect (whether to allow or block the install), and the rule causing
+ * that effect.
+ */
+public final class EvaluationOutcome {
+
+ public enum Effect {
+ ALLOW,
+ DENY
+ }
+
+ private final Effect mEffect;
+ private final Rule mRule;
+
+ private EvaluationOutcome(Effect effect, Rule rule) {
+ this.mEffect = effect;
+ this.mRule = rule;
+ }
+
+ public Effect getEffect() {
+ return mEffect;
+ }
+
+ public Rule getRule() {
+ return mRule;
+ }
+
+ /**
+ * Create an ALLOW evaluation outcome.
+ *
+ * @return An evaluation outcome with ALLOW effect and empty rule.
+ */
+ public static EvaluationOutcome allow() {
+ return new EvaluationOutcome(Effect.ALLOW, Rule.EMPTY);
+ }
+
+ /**
+ * Create a DENY evaluation outcome.
+ *
+ * @param rule Rule causing the DENY effect.
+ * @return An evaluation outcome with DENY effect and rule causing that effect.
+ */
+ public static EvaluationOutcome deny(Rule rule) {
+ return new EvaluationOutcome(Effect.DENY, rule);
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/model/OpenFormula.java b/services/core/java/com/android/server/integrity/model/OpenFormula.java
index 218cdc99c016..e9fa1a370611 100644
--- a/services/core/java/com/android/server/integrity/model/OpenFormula.java
+++ b/services/core/java/com/android/server/integrity/model/OpenFormula.java
@@ -16,9 +16,11 @@
package com.android.server.integrity.model;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
-import android.annotation.Nullable;
+import java.util.Collections;
+import java.util.List;
/**
* Represents a complex formula consisting of other simple and complex formulas.
@@ -34,46 +36,33 @@ public final class OpenFormula extends Formula {
}
private final Connector mConnector;
- private final Formula mMainFormula;
- private final Formula mAuxiliaryFormula;
+ private final List<Formula> mFormulas;
- public OpenFormula(Connector connector, Formula mainFormula,
- @Nullable Formula auxiliaryFormula) {
- validateAuxiliaryFormula(connector, auxiliaryFormula);
+ public OpenFormula(Connector connector, List<Formula> formulas) {
+ validateFormulas(connector, formulas);
this.mConnector = checkNotNull(connector);
- this.mMainFormula = checkNotNull(mainFormula);
- // TODO: Add validators on auxiliary formula
- this.mAuxiliaryFormula = auxiliaryFormula;
+ this.mFormulas = Collections.unmodifiableList(checkNotNull(formulas));
}
public Connector getConnector() {
return mConnector;
}
- public Formula getMainFormula() {
- return mMainFormula;
+ public List<Formula> getFormulas() {
+ return mFormulas;
}
- public Formula getAuxiliaryFormula() {
- return mAuxiliaryFormula;
- }
-
- private void validateAuxiliaryFormula(Connector connector, Formula auxiliaryFormula) {
- boolean validAuxiliaryFormula;
+ private void validateFormulas(Connector connector, List<Formula> formulas) {
switch (connector) {
case AND:
case OR:
- validAuxiliaryFormula = (auxiliaryFormula != null);
+ checkArgument(formulas.size() >= 2,
+ String.format("Connector %s must have at least 2 formulas", connector));
break;
case NOT:
- validAuxiliaryFormula = (auxiliaryFormula == null);
+ checkArgument(formulas.size() == 1,
+ String.format("Connector %s must have 1 formula only", connector));
break;
- default:
- validAuxiliaryFormula = false;
- }
- if (!validAuxiliaryFormula) {
- throw new IllegalArgumentException(
- String.format("Invalid formulas used for connector %s", connector));
}
}
}
diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java
index 4fd40c1e0365..3d233abda5ed 100644
--- a/services/core/java/com/android/server/integrity/model/Rule.java
+++ b/services/core/java/com/android/server/integrity/model/Rule.java
@@ -25,7 +25,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
*/
public final class Rule {
- enum Effect {
+ public enum Effect {
DENY
}
diff --git a/core/java/android/content/pm/PackageList.java b/services/core/java/com/android/server/pm/PackageList.java
index e3eb2c55a2bb..60bc8a87f62d 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/services/core/java/com/android/server/pm/PackageList.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.content.pm;
+package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e0697a636498..c53b81081d2f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -162,7 +162,6 @@ import android.content.pm.PackageBackwardCompatibility;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.ModuleInfoFlags;
@@ -3048,7 +3047,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
- mSetupWizardPackage = getSetupWizardPackageName();
+ mSetupWizardPackage = getSetupWizardPackageNameImpl();
mComponentResolver.fixProtectedFilterPriorities();
mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
@@ -19652,7 +19651,7 @@ public class PackageManagerService extends IPackageManager.Stub
set, comp, userId);
}
- private @Nullable String getSetupWizardPackageName() {
+ private @Nullable String getSetupWizardPackageNameImpl() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
@@ -19759,6 +19758,14 @@ public class PackageManagerService extends IPackageManager.Stub
return systemCaptionsServiceComponentName.getPackageName();
}
+ @Override
+ public String getSetupWizardPackageName() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Non-system caller");
+ }
+ return mPmInternal.getSetupWizardPackageName();
+ }
+
public String getIncidentReportApproverPackageName() {
return mContext.getString(R.string.config_incidentReportApproverPackage);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 237a7712ce9b..c851cc69a732 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4543,6 +4543,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void wakeUpFromPowerKey(long eventTime) {
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
+
+ // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
+ final HdmiControl hdmiControl = getHdmiControl();
+ if (hdmiControl != null) {
+ hdmiControl.turnOnTv();
+ }
}
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
@@ -4575,7 +4581,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// ... eventually calls finishWindowsDrawn which will finalize our screen turn on
// as well as enabling the orientation change logic/sensor.
mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
- WAITING_FOR_DRAWN_TIMEOUT);
+ WAITING_FOR_DRAWN_TIMEOUT, INVALID_DISPLAY);
}
// Called on the DisplayManager's DisplayPowerController thread.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 976fd52f17e5..4f52d9df817a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1723,25 +1723,27 @@ final class ActivityRecord extends AppWindowToken {
// implied that the current finishing activity should be added into stopping list rather
// than destroy immediately.
final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible);
- final ActivityStack stack = getActivityStack();
- final boolean notFocusedStack = stack != mRootActivityContainer.getTopDisplayFocusedStack();
+ final boolean notGlobalFocusedStack =
+ getActivityStack() != mRootActivityContainer.getTopDisplayFocusedStack();
if (isVisible && isNextNotYetVisible) {
+ // Add this activity to the list of stopping activities. It will be processed and
+ // destroyed when the next activity reports idle.
addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
"completeFinishing");
- if (DEBUG_STATES) {
- Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (finish requested)");
- }
setState(STOPPING, "completeFinishing");
- if (notFocusedStack) {
+ if (notGlobalFocusedStack) {
+ // Ensuring visibility and configuration only for non-focused stacks since this
+ // method call is relatively expensive and not necessary for focused stacks.
mRootActivityContainer.ensureVisibilityAndConfig(next, getDisplayId(),
false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
- } else if (isVisible && isState(PAUSED) && getActivityStack().isFocusedStackOnDisplay()
- && !inPinnedWindowingMode()) {
- // TODO(b/137329632): Currently non-focused stack is handled differently.
- addToFinishingAndWaitForIdle();
+ } else if (addToFinishingAndWaitForIdle()) {
+ // We added this activity to the finishing list and something else is becoming resumed.
+ // The activity will complete finishing when the next activity reports idle. No need to
+ // do anything else here.
} else {
- // Not waiting for the next one to become visible - finish right away.
+ // Not waiting for the next one to become visible, and nothing else will be resumed in
+ // place of this activity - requesting destruction right away.
activityRemoved = destroyIfPossible(reason);
}
@@ -1798,13 +1800,20 @@ final class ActivityRecord extends AppWindowToken {
return activityRemoved;
}
+ /**
+ * Add this activity to the list of finishing and trigger resuming of activities in focused
+ * stacks.
+ * @return {@code true} if some other activity is being resumed as a result of this call.
+ */
@VisibleForTesting
- void addToFinishingAndWaitForIdle() {
+ boolean addToFinishingAndWaitForIdle() {
if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this);
setState(FINISHING, "addToFinishingAndWaitForIdle");
- mStackSupervisor.mFinishingActivities.add(this);
+ if (!mStackSupervisor.mFinishingActivities.contains(this)) {
+ mStackSupervisor.mFinishingActivities.add(this);
+ }
resumeKeyDispatchingLocked();
- mRootActivityContainer.resumeFocusedStacksTopActivities();
+ return mRootActivityContainer.resumeFocusedStacksTopActivities();
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0844323e08fa..f592ac6957cb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -132,7 +132,6 @@ import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
-import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
@@ -3519,19 +3518,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
- void waitForAllWindowsDrawn() {
- final WindowManagerPolicy policy = mWmService.mPolicy;
- forAllWindows(w -> {
- final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
- if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
- w.mWinAnimator.mDrawState = DRAW_PENDING;
- // Force add to mResizingWindows.
- w.resetLastContentInsets();
- mWmService.mWaitingForDrawn.add(w);
- }
- }, true /* traverseTopToBottom */);
- }
-
// TODO: Super crazy long method that should be broken down...
void applySurfaceChangesTransaction(boolean recoveringMemory) {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ae3b5f2f70d3..d3e429019767 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -819,9 +819,12 @@ public class DockedStackDividerController {
// We put all tasks into drag resizing mode - wait until all of them have completed the
// drag resizing switch.
- if (!mService.mWaitingForDrawn.isEmpty()) {
- mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
+ final Runnable existingWaitingForDrwanCallback =
+ mService.mWaitingForDrawnCallbacks.get(mService.mRoot);
+ if (existingWaitingForDrwanCallback != null) {
+ mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, mService.mRoot);
+ mService.mH.sendMessageDelayed(mService.mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT,
+ mService.mRoot),
IME_ADJUST_DRAWN_TIMEOUT);
mAnimationStartDelayed = true;
if (imeWin != null) {
@@ -838,10 +841,8 @@ public class DockedStackDividerController {
// still gets executed.
// TODO: Have a real system where we can wait on different windows to be drawn with
// different callbacks.
- if (mService.mWaitingForDrawnCallback != null) {
- mService.mWaitingForDrawnCallback.run();
- }
- mService.mWaitingForDrawnCallback = () -> {
+ existingWaitingForDrwanCallback.run();
+ mService.mWaitingForDrawnCallbacks.put(mService.mRoot, () -> {
synchronized (mService.mGlobalLock) {
mAnimationStartDelayed = false;
if (mDelayedImeWin != null) {
@@ -863,7 +864,7 @@ public class DockedStackDividerController {
notifyAdjustedForImeChanged(
mAdjustedForIme || mAdjustedForDivider, duration);
}
- };
+ });
} else {
notifyAdjustedForImeChanged(
adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 013607e65367..5d27390da588 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import android.content.ComponentName;
-import android.content.pm.PackageList;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.Environment;
@@ -32,6 +31,7 @@ import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 0c8cd4330d70..6f10d3d291b1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -720,7 +720,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mUpdateRotation = updateRotationUnchecked();
}
- if (mWmService.mWaitingForDrawnCallback != null
+ if (!mWmService.mWaitingForDrawnCallbacks.isEmpty()
|| (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 19fcb1b96e7b..a4ab66aef550 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -33,6 +33,7 @@ import static com.android.server.wm.WindowContainerProto.VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import android.annotation.CallSuper;
import android.annotation.IntDef;
@@ -54,9 +55,11 @@ import android.view.SurfaceSession;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
+import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.SurfaceAnimator.Animatable;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.function.Consumer;
@@ -124,6 +127,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
private final Transaction mPendingTransaction;
/**
+ * Windows that clients are waiting to have drawn.
+ */
+ final ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
+
+ /**
* Applied as part of the animation pass in "prepareSurfaces".
*/
protected final SurfaceAnimator mSurfaceAnimator;
@@ -1434,6 +1442,19 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
+ void waitForAllWindowsDrawn() {
+ final WindowManagerPolicy policy = mWmService.mPolicy;
+ forAllWindows(w -> {
+ final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
+ if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
+ w.mWinAnimator.mDrawState = DRAW_PENDING;
+ // Force add to mResizingWindows.
+ w.resetLastContentInsets();
+ mWaitingForDrawn.add(w);
+ }
+ }, true /* traverseTopToBottom */);
+ }
+
Dimmer getDimmer() {
if (mParent == null) {
return null;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index bb3caa9ed4ed..f4b76729b7ea 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -313,10 +313,15 @@ public abstract class WindowManagerInternal {
public abstract void showGlobalActions();
/**
- * Invalidate all visible windows. Then report back on the callback once all windows have
- * redrawn.
+ * Invalidate all visible windows on a given display, and report back on the callback when all
+ * windows have redrawn.
+ *
+ * @param callback reporting callback to be called when all windows have redrawn.
+ * @param timeout calls the callback anyway after the timeout.
+ * @param displayId waits for the windows on the given display, INVALID_DISPLAY to wait for all
+ * windows on all displays.
*/
- public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout);
+ public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId);
/**
* Overrides the display size.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 20812e98bf4a..0f4d0a8662f4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -290,6 +290,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -568,13 +569,10 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
/**
- * Windows that clients are waiting to have drawn.
+ * The callbacks to make when the windows all have been drawn for a given
+ * {@link WindowContainer}.
*/
- ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
- /**
- * And the callback to make when they've all been drawn.
- */
- Runnable mWaitingForDrawnCallback;
+ final HashMap<WindowContainer, Runnable> mWaitingForDrawnCallbacks = new HashMap<>();
/** List of window currently causing non-system overlay windows to be hidden. */
private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
@@ -4736,12 +4734,12 @@ public class WindowManagerService extends IWindowManager.Stub
case WAITING_FOR_DRAWN_TIMEOUT: {
Runnable callback = null;
+ final WindowContainer container = (WindowContainer) msg.obj;
synchronized (mGlobalLock) {
ProtoLog.w(WM_ERROR, "Timeout waiting for drawn: undrawn=%s",
- mWaitingForDrawn);
- mWaitingForDrawn.clear();
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
+ container.mWaitingForDrawn);
+ container.mWaitingForDrawn.clear();
+ callback = mWaitingForDrawnCallbacks.remove(container);
}
if (callback != null) {
callback.run();
@@ -4773,9 +4771,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
case ALL_WINDOWS_DRAWN: {
Runnable callback;
+ final WindowContainer container = (WindowContainer) msg.obj;
synchronized (mGlobalLock) {
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
+ callback = mWaitingForDrawnCallbacks.remove(container);
}
if (callback != null) {
callback.run();
@@ -5265,30 +5263,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
void checkDrawnWindowsLocked() {
- if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
+ if (mWaitingForDrawnCallbacks.isEmpty()) {
return;
}
- for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
- WindowState win = mWaitingForDrawn.get(j);
- ProtoLog.i(WM_DEBUG_SCREEN_ON,
+ mWaitingForDrawnCallbacks.forEach((container, callback) -> {
+ for (int j = container.mWaitingForDrawn.size() - 1; j >= 0; j--) {
+ final WindowState win = (WindowState) container.mWaitingForDrawn.get(j);
+ ProtoLog.i(WM_DEBUG_SCREEN_ON,
"Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
win, win.mRemoved, win.isVisibleLw(), win.mHasSurface,
win.mWinAnimator.mDrawState);
- if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
- // Window has been removed or hidden; no draw will now happen, so stop waiting.
- ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
- mWaitingForDrawn.remove(win);
- } else if (win.hasDrawnLw()) {
- // Window is now drawn (and shown).
- ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
- mWaitingForDrawn.remove(win);
+ if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
+ // Window has been removed or hidden; no draw will now happen, so stop waiting.
+ ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
+ container.mWaitingForDrawn.remove(win);
+ } else if (win.hasDrawnLw()) {
+ // Window is now drawn (and shown).
+ ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
+ container.mWaitingForDrawn.remove(win);
+ }
}
- }
- if (mWaitingForDrawn.isEmpty()) {
- ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
- }
+ if (container.mWaitingForDrawn.isEmpty()) {
+ ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
+ mH.sendMessage(mH.obtainMessage(H.ALL_WINDOWS_DRAWN, container));
+ }
+ });
}
void setHoldScreenLocked(final Session newHoldScreen) {
@@ -5934,13 +5934,18 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
- if (mWaitingForDrawn.size() > 0) {
+ if (!mWaitingForDrawnCallbacks.isEmpty()) {
pw.println();
pw.println(" Clients waiting for these windows to be drawn:");
- for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
- WindowState win = mWaitingForDrawn.get(i);
- pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(win);
- }
+ mWaitingForDrawnCallbacks.forEach((wc, callback) -> {
+ pw.print(" WindowContainer ");
+ pw.println(wc.getName());
+ for (int i = wc.mWaitingForDrawn.size() - 1; i >= 0; i--) {
+ final WindowState win = (WindowState) wc.mWaitingForDrawn.get(i);
+ pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(win);
+ }
+ });
+
}
pw.println();
pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration());
@@ -7096,17 +7101,25 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
+ public void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId) {
+ final WindowContainer container = displayId == INVALID_DISPLAY
+ ? mRoot : mRoot.getDisplayContent(displayId);
+ if (container == null) {
+ // The waiting container doesn't exist, no need to wait to run the callback. Run and
+ // return;
+ callback.run();
+ return;
+ }
boolean allWindowsDrawn = false;
synchronized (mGlobalLock) {
- mWaitingForDrawnCallback = callback;
- getDefaultDisplayContentLocked().waitForAllWindowsDrawn();
+ container.waitForAllWindowsDrawn();
mWindowPlacerLocked.requestTraversal();
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- if (mWaitingForDrawn.isEmpty()) {
+ mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
+ if (container.mWaitingForDrawn.isEmpty()) {
allWindowsDrawn = true;
} else {
- mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
+ mWaitingForDrawnCallbacks.put(container, callback);
+ mH.sendNewMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, container, timeout);
checkDrawnWindowsLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 82b9d460029d..56e08b2843b5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3497,7 +3497,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
void setWaitingForDrawnIfResizingChanged() {
if (isDragResizeChanged()) {
- mWmService.mWaitingForDrawn.add(this);
+ mWmService.mRoot.mWaitingForDrawn.add(this);
}
super.setWaitingForDrawnIfResizingChanged();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b118cdfeb84d..47291cb286ba 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11320,6 +11320,28 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ @Override
+ public boolean isActiveSupervisionApp(int uid) {
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
+ null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, uid);
+ if (admin == null) {
+ return false;
+ }
+
+ final String supervisionString = mContext.getResources().getString(
+ com.android.internal.R.string
+ .config_defaultSupervisionProfileOwnerComponent);
+ if (supervisionString == null) {
+ return false;
+ }
+
+ final ComponentName supervisorComponent = ComponentName.unflattenFromString(
+ supervisionString);
+ return admin.info.getComponent().equals(supervisorComponent);
+ }
+ }
+
private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (getLockObject()) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index a25e40f8cc13..9a1fd9cf0e12 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2650,6 +2650,21 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verifyStayOnWhilePluggedCleared(false);
}
+ public void testIsActiveSupervisionApp() throws Exception {
+ when(mServiceContext.resources
+ .getString(R.string.config_defaultSupervisionProfileOwnerComponent))
+ .thenReturn(admin1.flattenToString());
+
+ final int PROFILE_USER = 15;
+ final int PROFILE_ADMIN = UserHandle.getUid(PROFILE_USER, 19436);
+ addManagedProfile(admin1, PROFILE_ADMIN, admin1);
+ mContext.binder.callingUid = PROFILE_ADMIN;
+
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ assertTrue(dpmi.isActiveSupervisionApp(PROFILE_ADMIN));
+ }
+
// Test if lock timeout on managed profile is handled correctly depending on whether profile
// uses separate challenge.
public void testSetMaximumTimeToLockProfile() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
index 1a3dde0cb838..2133a7d3550b 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
@@ -24,6 +24,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.Arrays;
+import java.util.Collections;
+
@RunWith(JUnit4.class)
public class OpenFormulaTest {
@@ -34,12 +37,11 @@ public class OpenFormulaTest {
@Test
public void testValidOpenFormula() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND, ATOMIC_FORMULA_1,
- ATOMIC_FORMULA_2);
+ OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
assertEquals(OpenFormula.Connector.AND, openFormula.getConnector());
- assertEquals(ATOMIC_FORMULA_1, openFormula.getMainFormula());
- assertEquals(ATOMIC_FORMULA_2, openFormula.getAuxiliaryFormula());
+ assertEquals(Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), openFormula.getFormulas());
}
@Test
@@ -47,9 +49,10 @@ public class OpenFormulaTest {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Invalid formulas used for connector %s", OpenFormula.Connector.AND),
- () -> new OpenFormula(OpenFormula.Connector.AND, ATOMIC_FORMULA_1,
- null));
+ String.format("Connector %s must have at least 2 formulas",
+ OpenFormula.Connector.AND),
+ () -> new OpenFormula(OpenFormula.Connector.AND,
+ Collections.singletonList(ATOMIC_FORMULA_1)));
}
@Test
@@ -57,8 +60,8 @@ public class OpenFormulaTest {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format("Invalid formulas used for connector %s", OpenFormula.Connector.NOT),
- () -> new OpenFormula(OpenFormula.Connector.NOT, ATOMIC_FORMULA_1,
- ATOMIC_FORMULA_2));
+ String.format("Connector %s must have 1 formula only", OpenFormula.Connector.NOT),
+ () -> new OpenFormula(OpenFormula.Connector.NOT,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 7115af9f1ee9..b9fef4b008c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -32,7 +32,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import android.content.ComponentName;
-import android.content.pm.PackageList;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.UserHandle;
@@ -43,6 +42,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
index 778f0ca3c782..9c3ff654ddf0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java
@@ -22,8 +22,11 @@ import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static org.mockito.ArgumentMatchers.any;
+
import android.hardware.display.DisplayManagerGlobal;
import android.view.Display;
import android.view.DisplayInfo;
@@ -85,6 +88,10 @@ class TestActivityDisplay extends ActivityDisplay {
displayRotation.setRotation(rotation);
return true;
}).when(displayRotation).updateRotationUnchecked(anyBoolean());
+
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
+ spyOn(inputMonitor);
+ doNothing().when(inputMonitor).resumeDispatchingLw(any());
}
@SuppressWarnings("TypeParameterUnusedInFormals")
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 34eb3f16bf2a..ecee709054ee 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1733,10 +1733,13 @@ public class UsageStatsService extends SystemService implements
public void registerAppUsageLimitObserver(int observerId, String[] packages,
long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent,
String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
- Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
- throw new SecurityException("Caller doesn't have both SUSPEND_APPS and "
- + "OBSERVE_APP_USAGE permissions");
+ Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
+ && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ throw new SecurityException("Caller must be the active supervision app or "
+ + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
if (packages == null || packages.length == 0) {
@@ -1745,7 +1748,6 @@ public class UsageStatsService extends SystemService implements
if (callbackIntent == null && timeUsedMs < timeLimitMs) {
throw new NullPointerException("callbackIntent can't be null");
}
- final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
@@ -1758,13 +1760,15 @@ public class UsageStatsService extends SystemService implements
@Override
public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
if (!hasPermissions(callingPackage,
- Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
- throw new SecurityException("Caller doesn't have both SUSPEND_APPS and "
- + "OBSERVE_APP_USAGE permissions");
+ Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
+ && (dpmInternal != null && !dpmInternal.isActiveSupervisionApp(callingUid))) {
+ throw new SecurityException("Caller must be the active supervision app or "
+ + "it must have both SUSPEND_APPS and OBSERVE_APP_USAGE permissions");
}
- final int callingUid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(callingUid);
final long token = Binder.clearCallingIdentity();
try {
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 28747dab38db..9ff851598648 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -104,7 +104,7 @@ public final class TelephonyScanManager {
private final Looper mLooper;
private final Messenger mMessenger;
- private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
+ private final SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
public TelephonyScanManager() {
HandlerThread thread = new HandlerThread(TAG);
@@ -204,14 +204,16 @@ public final class TelephonyScanManager {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
+ synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
+ saveScanInfo(scanId, request, executor, callback);
+ return new NetworkScan(scanId, subId);
}
- saveScanInfo(scanId, request, executor, callback);
- return new NetworkScan(scanId, subId);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "requestNetworkScan RemoteException", ex);
@@ -223,9 +225,7 @@ public final class TelephonyScanManager {
private void saveScanInfo(
int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
- synchronized (mScanInfo) {
- mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
- }
+ mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
}
private ITelephony getITelephony() {
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index c9ec0f86a9dc..c19ae7b3916a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -170,7 +170,7 @@ public class PhoneConstants {
public static final int RIL_CARD_MAX_APPS = 8;
- public static final int DEFAULT_CARD_INDEX = 0;
+ public static final int DEFAULT_SLOT_INDEX = 0;
public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index b0464d9e656f..ae8285b8a908 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -99,6 +99,7 @@ public class LinkPropertiesTest {
assertFalse(lp.isIpv4Provisioned());
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
+ assertFalse(lp.isWakeOnLanSupported());
}
private LinkProperties makeTestObject() {
@@ -120,6 +121,7 @@ public class LinkPropertiesTest {
lp.setMtu(MTU);
lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
+ lp.setWakeOnLanSupported(true);
return lp;
}
@@ -158,6 +160,9 @@ public class LinkPropertiesTest {
assertTrue(source.isIdenticalTcpBufferSizes(target));
assertTrue(target.isIdenticalTcpBufferSizes(source));
+ assertTrue(source.isIdenticalWakeOnLan(target));
+ assertTrue(target.isIdenticalWakeOnLan(source));
+
// Check result of equals().
assertTrue(source.equals(target));
assertTrue(target.equals(source));
@@ -1057,4 +1062,13 @@ public class LinkPropertiesTest {
lp.clear();
assertFalse(lp.isPrivateDnsActive());
}
+
+ @Test
+ public void testWakeOnLanSupported() {
+ final LinkProperties lp = makeTestObject();
+ assertTrue(lp.isWakeOnLanSupported());
+
+ lp.clear();
+ assertFalse(lp.isWakeOnLanSupported());
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 41440abadcd0..bffbbfda08ee 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -274,6 +274,7 @@ public class ConnectivityServiceTest {
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
+ private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
@@ -343,6 +344,12 @@ public class ConnectivityServiceTest {
"mobile_mms,2,0,2,60000,true",
});
+ when(mResources.getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces))
+ .thenReturn(new String[]{
+ WIFI_WOL_IFNAME,
+ });
+
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -5947,6 +5954,24 @@ public class ConnectivityServiceTest {
assertContainsExactly(uidCaptor.getValue(), APP2_UID);
}
+ @Test
+ public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+ LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
+ wifiLp.setWakeOnLanSupported(false);
+
+ // Default network switch should update ifaces.
+ mWiFiNetworkAgent.connect(false);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ waitForIdle();
+
+ // ConnectivityService should have changed the WakeOnLanSupported to true
+ wifiLp.setWakeOnLanSupported(true);
+ assertEquals(wifiLp, mService.getActiveLinkProperties());
+ }
+
private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
Set<UidRange> vpnRange) throws Exception {
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 702921836b0d..3fdba6eac55d 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -54,7 +54,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
@@ -70,6 +69,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageList;
import org.junit.Before;
import org.junit.Test;