diff options
120 files changed, 2339 insertions, 993 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/api/current.txt b/api/current.txt index 3a768ea98eb2..e6e2b40cbb19 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; @@ -45170,6 +45172,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>); method public boolean setLine1NumberForDisplay(String, String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 8ed79a3f2338..4db7f4a537ec 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6557,7 +6557,8 @@ package android.service.euicc { method public abstract int onDeleteSubscription(int, String); method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle); method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean); - method public abstract int onEraseSubscriptions(int); + method @Deprecated public abstract int onEraseSubscriptions(int); + method public int onEraseSubscriptionsWithOptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int); method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean); method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean); method public abstract String onGetEid(int); @@ -8620,7 +8621,8 @@ package android.telephony.euicc { public class EuiccManager { method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle); - method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(android.app.PendingIntent); + method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent); + method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptionsWithOptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus(); 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/ActivityThread.java b/core/java/android/app/ActivityThread.java index 38aac1b47f65..7f27368e017e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1163,6 +1163,10 @@ public final class ActivityThread extends ClientTransactionHandler { sendMessage(H.ATTACH_AGENT, agent); } + public void attachStartupAgents(String dataDir) { + sendMessage(H.ATTACH_STARTUP_AGENTS, dataDir); + } + public void setSchedulingGroup(int group) { // Note: do this immediately, since going into the foreground // should happen regardless of what pending work we have to do @@ -1812,6 +1816,7 @@ public final class ActivityThread extends ClientTransactionHandler { public static final int EXECUTE_TRANSACTION = 159; public static final int RELAUNCH_ACTIVITY = 160; public static final int PURGE_RESOURCES = 161; + public static final int ATTACH_STARTUP_AGENTS = 162; String codeToString(int code) { if (DEBUG_MESSAGES) { @@ -1855,6 +1860,7 @@ public final class ActivityThread extends ClientTransactionHandler { case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION"; case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY"; case PURGE_RESOURCES: return "PURGE_RESOURCES"; + case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS"; } } return Integer.toString(code); @@ -2043,6 +2049,9 @@ public final class ActivityThread extends ClientTransactionHandler { case PURGE_RESOURCES: schedulePurgeIdler(); break; + case ATTACH_STARTUP_AGENTS: + handleAttachStartupAgents((String) msg.obj); + break; } Object obj = msg.obj; if (obj instanceof SomeArgs) { @@ -3779,6 +3788,27 @@ public final class ActivityThread extends ClientTransactionHandler { } } + static void handleAttachStartupAgents(String dataDir) { + try { + Path code_cache = ContextImpl.getCodeCacheDirBeforeBind(new File(dataDir)).toPath(); + if (!Files.exists(code_cache)) { + return; + } + Path startup_path = code_cache.resolve("startup_agents"); + if (Files.exists(startup_path)) { + for (Path p : Files.newDirectoryStream(startup_path)) { + handleAttachAgent( + p.toAbsolutePath().toString() + + "=" + + dataDir, + null); + } + } + } catch (Exception e) { + // Ignored. + } + } + private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>(); /** @@ -6427,26 +6457,6 @@ public final class ActivityThread extends ClientTransactionHandler { NetworkSecurityConfigProvider.install(appContext); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - - if (isAppDebuggable) { - try { - // Load all the agents in the code_cache/startup_agents directory. - // We pass the absolute path to the data_dir as an argument. - Path startup_path = appContext.getCodeCacheDir().toPath().resolve("startup_agents"); - if (Files.exists(startup_path)) { - for (Path p : Files.newDirectoryStream(startup_path)) { - handleAttachAgent( - p.toAbsolutePath().toString() - + "=" - + appContext.getDataDir().toPath().toAbsolutePath().toString(), - data.info); - } - } - } catch (Exception e) { - // Ignored. - } - } - // Continue loading instrumentation. if (ii != null) { ApplicationInfo instrApp; 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/ContextImpl.java b/core/java/android/app/ContextImpl.java index ef23d5e7a424..5b211e147d64 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -741,12 +741,21 @@ class ContextImpl extends Context { public File getCodeCacheDir() { synchronized (mSync) { if (mCodeCacheDir == null) { - mCodeCacheDir = new File(getDataDir(), "code_cache"); + mCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir()); } return ensurePrivateCacheDirExists(mCodeCacheDir, XATTR_INODE_CODE_CACHE); } } + /** + * Helper for getting code-cache dir potentially before application bind. + * + * @hide + */ + static File getCodeCacheDirBeforeBind(File dataDir) { + return new File(dataDir, "code_cache"); + } + @Override public File getExternalCacheDir() { // Operates on primary external storage diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index cfa065ba5bc9..51a64fff7c45 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -137,6 +137,7 @@ oneway interface IApplicationThread { IVoiceInteractor voiceInteractor); void handleTrustStorageUpdate(); void attachAgent(String path); + void attachStartupAgents(String dataDir); void scheduleApplicationInfoChanged(in ApplicationInfo ai); void setNetworkBlockSeq(long procStateSeq); void scheduleTransaction(in ClientTransaction transaction); 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/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 9f0bade9bd29..ccfa1843200c 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -350,7 +350,7 @@ public class UserInfo implements Parcelable { @UnsupportedAppUsage public UserHandle getUserHandle() { - return new UserHandle(id); + return UserHandle.of(id); } @Override diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index ff8b13506201..8a9f68942e9d 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -15,6 +15,8 @@ */ package android.service.euicc; +import static android.telephony.euicc.EuiccCardManager.ResetOption; + import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; @@ -503,7 +505,7 @@ public abstract class EuiccService extends Service { String nickname); /** - * Erase all of the subscriptions on the device. + * Erase all operational subscriptions on the device. * * <p>This is intended to be used for device resets. As such, the reset should be performed even * if an active SIM must be deactivated in order to access the eUICC. @@ -512,10 +514,31 @@ public abstract class EuiccService extends Service { * @return the result of the erase operation. May be one of the predefined {@code RESULT_} * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#eraseSubscriptions + * + * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase + * and use @link{onEraseSubscriptionsWithOptions} instead */ + @Deprecated public abstract int onEraseSubscriptions(int slotId); /** + * Erase specific subscriptions on the device. + * + * <p>This is intended to be used for device resets. As such, the reset should be performed even + * if an active SIM must be deactivated in order to access the eUICC. + * + * @param slotIndex index of the SIM slot to use for the operation. + * @param options flag for specific group of subscriptions to erase + * @return the result of the erase operation. May be one of the predefined {@code RESULT_} + * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. + * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions + */ + public int onEraseSubscriptionsWithOptions(int slotIndex, @ResetOption int options) { + throw new UnsupportedOperationException( + "This method must be overridden to enable the ResetOption parameter"); + } + + /** * Ensure that subscriptions will be retained on the next factory reset. * * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to @@ -751,6 +774,23 @@ public abstract class EuiccService extends Service { } @Override + public void eraseSubscriptionsWithOptions( + int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + int result = EuiccService.this.onEraseSubscriptionsWithOptions( + slotIndex, options); + try { + callback.onComplete(result); + } catch (RemoteException e) { + // Can't communicate with the phone process; ignore. + } + } + }); + } + + @Override public void retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback) { mExecutor.execute(new Runnable() { diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl index c2cdf093706f..2acc47aae919 100644 --- a/core/java/android/service/euicc/IEuiccService.aidl +++ b/core/java/android/service/euicc/IEuiccService.aidl @@ -52,6 +52,8 @@ oneway interface IEuiccService { void updateSubscriptionNickname(int slotId, String iccid, String nickname, in IUpdateSubscriptionNicknameCallback callback); void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback); + void eraseSubscriptionsWithOptions( + int slotIndex, int options, in IEraseSubscriptionsCallback callback); void retainSubscriptionsForFactoryReset( int slotId, in IRetainSubscriptionsForFactoryResetCallback callback); }
\ No newline at end of file diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b685cf098b33..6637c5b06a1b 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -181,7 +181,6 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSeverChildren(long transactionObj, long nativeObject); private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject, int scalingMode); - private static native boolean nativeGetTransformToDisplayInverse(long nativeObject); private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken); @@ -303,8 +302,8 @@ public final class SurfaceControl implements Parcelable { /** * Surface creation flag: Creates a Dim surface. * Everything behind this surface is dimmed by the amount specified - * in {@link #setAlpha}. It is an error to lock a Dim surface, since it - * doesn't have a backing store. + * in {@link Transaction#setAlpha(SurfaceControl, float)}. It is an error to lock a Dim + * surface, since it doesn't have a backing store. * * @hide */ @@ -740,20 +739,20 @@ public final class SurfaceControl implements Parcelable { * <p> * Good practice is to first create the surface with the {@link #HIDDEN} flag * specified, open a transaction, set the surface layer, layer stack, alpha, - * and position, call {@link #show} if appropriate, and close the transaction. + * and position, call {@link Transaction#show(SurfaceControl)} if appropriate, and close the + * transaction. * <p> * Bounds of the surface is determined by its crop and its buffer size. If the * surface has no buffer or crop, the surface is boundless and only constrained * by the size of its parent bounds. * - * @param session The surface session, must not be null. - * @param name The surface name, must not be null. - * @param w The surface initial width. - * @param h The surface initial height. - * @param flags The surface creation flags. Should always include {@link #HIDDEN} - * in the creation flags. + * @param session The surface session, must not be null. + * @param name The surface name, must not be null. + * @param w The surface initial width. + * @param h The surface initial height. + * @param flags The surface creation flags. Should always include {@link #HIDDEN} + * in the creation flags. * @param metadata Initial metadata. - * * @throws throws OutOfResourcesException If the SurfaceControl cannot be created. */ private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags, @@ -1014,15 +1013,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public void deferTransactionUntil(Surface barrier, long frame) { - synchronized(SurfaceControl.class) { - sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame); - } - } - - /** - * @hide - */ public void reparentChildren(SurfaceControl newParent) { synchronized(SurfaceControl.class) { sGlobalTransaction.reparentChildren(this, newParent); @@ -1032,15 +1022,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public void reparent(SurfaceControl newParent) { - synchronized(SurfaceControl.class) { - sGlobalTransaction.reparent(this, newParent); - } - } - - /** - * @hide - */ public void detachChildren() { synchronized(SurfaceControl.class) { sGlobalTransaction.detachChildren(this); @@ -1060,15 +1041,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public static void setAnimationTransaction() { - synchronized (SurfaceControl.class) { - sGlobalTransaction.setAnimationTransaction(); - } - } - - /** - * @hide - */ @UnsupportedAppUsage public void setLayer(int zorder) { checkNotReleased(); @@ -1080,16 +1052,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public void setRelativeLayer(SurfaceControl relativeTo, int zorder) { - checkNotReleased(); - synchronized(SurfaceControl.class) { - sGlobalTransaction.setRelativeLayer(this, relativeTo, zorder); - } - } - - /** - * @hide - */ @UnsupportedAppUsage public void setPosition(float x, float y) { checkNotReleased(); @@ -1183,16 +1145,6 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public void setColor(@Size(3) float[] color) { - checkNotReleased(); - synchronized (SurfaceControl.class) { - sGlobalTransaction.setColor(this, color); - } - } - - /** - * @hide - */ public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { checkNotReleased(); synchronized(SurfaceControl.class) { @@ -1201,36 +1153,6 @@ public final class SurfaceControl implements Parcelable { } /** - * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation matrix. - * - * @param matrix The matrix to apply. - * @param float9 An array of 9 floats to be used to extract the values from the matrix. - * @hide - */ - public void setMatrix(Matrix matrix, float[] float9) { - checkNotReleased(); - matrix.getValues(float9); - synchronized (SurfaceControl.class) { - sGlobalTransaction.setMatrix(this, float9[MSCALE_X], float9[MSKEW_Y], - float9[MSKEW_X], float9[MSCALE_Y]); - sGlobalTransaction.setPosition(this, float9[MTRANS_X], float9[MTRANS_Y]); - } - } - - /** - * Sets the color transform for the Surface. - * @param matrix A float array with 9 values represents a 3x3 transform matrix - * @param translation A float array with 3 values represents a translation vector - * @hide - */ - public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) { - checkNotReleased(); - synchronized (SurfaceControl.class) { - sGlobalTransaction.setColorTransform(this, matrix, translation); - } - } - - /** * Sets the Surface to be color space agnostic. If a surface is color space agnostic, * the color can be interpreted in any color space. * @param agnostic A boolean to indicate whether the surface is color space agnostic @@ -1260,43 +1182,6 @@ public final class SurfaceControl implements Parcelable { } /** - * Same as {@link SurfaceControl#setWindowCrop(Rect)} but sets the crop rect top left at 0, 0. - * - * @param width width of crop rect - * @param height height of crop rect - * @hide - */ - public void setWindowCrop(int width, int height) { - checkNotReleased(); - synchronized (SurfaceControl.class) { - sGlobalTransaction.setWindowCrop(this, width, height); - } - } - - /** - * Sets the corner radius of a {@link SurfaceControl}. - * - * @param cornerRadius Corner radius in pixels. - * @hide - */ - public void setCornerRadius(float cornerRadius) { - checkNotReleased(); - synchronized (SurfaceControl.class) { - sGlobalTransaction.setCornerRadius(this, cornerRadius); - } - } - - /** - * @hide - */ - public void setLayerStack(int layerStack) { - checkNotReleased(); - synchronized(SurfaceControl.class) { - sGlobalTransaction.setLayerStack(this, layerStack); - } - } - - /** * @hide */ public void setOpaque(boolean isOpaque) { @@ -2302,6 +2187,12 @@ public final class SurfaceControl implements Parcelable { } /** + * Sets the transform and position of a {@link SurfaceControl} from a 3x3 transformation + * matrix. + * + * @param sc SurfaceControl to set matrix of + * @param matrix The matrix to apply. + * @param float9 An array of 9 floats to be used to extract the values from the matrix. * @hide */ @UnsupportedAppUsage @@ -2315,7 +2206,9 @@ public final class SurfaceControl implements Parcelable { /** * Sets the color transform for the Surface. - * @param matrix A float array with 9 values represents a 3x3 transform matrix + * + * @param sc SurfaceControl to set color transform of + * @param matrix A float array with 9 values represents a 3x3 transform matrix * @param translation A float array with 3 values represents a translation vector * @hide */ @@ -2339,6 +2232,13 @@ public final class SurfaceControl implements Parcelable { } /** + * Bounds the surface and its children to the bounds specified. Size of the surface will be + * ignored and only the crop and buffer size will be used to determine the bounds of the + * surface. If no crop is specified and the surface has no buffer, the surface bounds is + * only constrained by the size of its parent bounds. + * + * @param sc SurfaceControl to set crop of. + * @param crop Bounds of the crop to apply. * @hide */ @UnsupportedAppUsage @@ -2355,6 +2255,12 @@ public final class SurfaceControl implements Parcelable { } /** + * Same as {@link Transaction#setWindowCrop(SurfaceControl, Rect)} but sets the crop rect + * top left at 0, 0. + * + * @param sc SurfaceControl to set crop of. + * @param width width of crop rect + * @param height height of crop rect * @hide */ public Transaction setWindowCrop(SurfaceControl sc, int width, int height) { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index a85830009f58..2f0a4ebb84f8 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -418,12 +418,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall Log.d(TAG, System.identityHashCode(this) + " updateSurfaceAlpha: set alpha=" + alpha); } - SurfaceControl.openTransaction(); - try { - mSurfaceControl.setAlpha(alpha); - } finally { - SurfaceControl.closeTransaction(); - } + mTmpTransaction.setAlpha(mSurfaceControl, alpha).apply(); } mSurfaceAlpha = alpha; } @@ -701,17 +696,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void updateBackgroundVisibilityInTransaction() { + private void updateBackgroundVisibility(Transaction t) { if (mBackgroundControl == null) { return; } if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) { - mBackgroundControl.show(); + t.show(mBackgroundControl); } else { - mBackgroundControl.hide(); + t.hide(mBackgroundControl); } } + private void releaseSurfaces() { mSurfaceAlpha = 1f; @@ -853,61 +849,61 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Cur surface: " + mSurface); - SurfaceControl.openTransaction(); - try { - // If we are creating the surface control or the parent surface has not - // changed, then set relative z. Otherwise allow the parent - // SurfaceChangedCallback to update the relative z. This is needed so that - // we do not change the relative z before the server is ready to swap the - // parent surface. - if (creating || (mParentSurfaceGenerationId - == viewRoot.mSurface.getGenerationId())) { - SurfaceControl.mergeToGlobalTransaction(updateRelativeZ()); - } - mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId(); + // If we are creating the surface control or the parent surface has not + // changed, then set relative z. Otherwise allow the parent + // SurfaceChangedCallback to update the relative z. This is needed so that + // we do not change the relative z before the server is ready to swap the + // parent surface. + if (creating || (mParentSurfaceGenerationId + == viewRoot.mSurface.getGenerationId())) { + updateRelativeZ(mTmpTransaction); + } + mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId(); - if (mViewVisibility) { - mSurfaceControl.show(); - } else { - mSurfaceControl.hide(); - } - updateBackgroundVisibilityInTransaction(); - if (mUseAlpha) { - mSurfaceControl.setAlpha(alpha); - mSurfaceAlpha = alpha; - } + if (mViewVisibility) { + mTmpTransaction.show(mSurfaceControl); + } else { + mTmpTransaction.hide(mSurfaceControl); + } + updateBackgroundVisibility(mTmpTransaction); + if (mUseAlpha) { + mTmpTransaction.setAlpha(mSurfaceControl, alpha); + mSurfaceAlpha = alpha; + } - // While creating the surface, we will set it's initial - // geometry. Outside of that though, we should generally - // leave it to the RenderThread. - // - // There is one more case when the buffer size changes we aren't yet - // prepared to sync (as even following the transaction applying - // we still need to latch a buffer). - // b/28866173 - if (sizeChanged || creating || !mRtHandlingPositionUpdates) { - mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top); - mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth, - 0.0f, 0.0f, - mScreenRect.height() / (float) mSurfaceHeight); - // Set a window crop when creating the surface or changing its size to - // crop the buffer to the surface size since the buffer producer may - // use SCALING_MODE_SCALE and submit a larger size than the surface - // size. - if (mClipSurfaceToBounds && mClipBounds != null) { - mSurfaceControl.setWindowCrop(mClipBounds); - } else { - mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight); - } - } - mSurfaceControl.setCornerRadius(mCornerRadius); - if (sizeChanged && !creating) { - mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight); + // While creating the surface, we will set it's initial + // geometry. Outside of that though, we should generally + // leave it to the RenderThread. + // + // There is one more case when the buffer size changes we aren't yet + // prepared to sync (as even following the transaction applying + // we still need to latch a buffer). + // b/28866173 + if (sizeChanged || creating || !mRtHandlingPositionUpdates) { + mTmpTransaction.setPosition(mSurfaceControl, mScreenRect.left, + mScreenRect.top); + mTmpTransaction.setMatrix(mSurfaceControl, + mScreenRect.width() / (float) mSurfaceWidth, 0.0f, 0.0f, + mScreenRect.height() / (float) mSurfaceHeight); + // Set a window crop when creating the surface or changing its size to + // crop the buffer to the surface size since the buffer producer may + // use SCALING_MODE_SCALE and submit a larger size than the surface + // size. + if (mClipSurfaceToBounds && mClipBounds != null) { + mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds); + } else { + mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth, + mSurfaceHeight); } - } finally { - SurfaceControl.closeTransaction(); + } + mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); + if (sizeChanged && !creating) { + mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth, + mSurfaceHeight); } + mTmpTransaction.apply(); + if (sizeChanged || creating) { redrawNeeded = true; } @@ -1260,12 +1256,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f, Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f }; - SurfaceControl.openTransaction(); - try { - mBackgroundControl.setColor(colorComponents); - } finally { - SurfaceControl.closeTransaction(); - } + mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply(); } @UnsupportedAppUsage @@ -1480,15 +1471,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void surfaceReplaced(Transaction t) { if (mSurfaceControl != null && mBackgroundControl != null) { - t.merge(updateRelativeZ()); + updateRelativeZ(t); } } - private Transaction updateRelativeZ() { - Transaction t = new Transaction(); + private void updateRelativeZ(Transaction t) { SurfaceControl viewRoot = getViewRootImpl().getSurfaceControl(); t.setRelativeLayer(mBackgroundControl, viewRoot, Integer.MIN_VALUE); t.setRelativeLayer(mSurfaceControl, viewRoot, mSubLayer); - return t; } } diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java index e09e0e609380..cffb0ad9fdb9 100644 --- a/core/java/com/android/internal/os/KernelWakelockReader.java +++ b/core/java/com/android/internal/os/KernelWakelockReader.java @@ -29,6 +29,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.io.FileInputStream; +import java.util.Arrays; import java.util.Iterator; /** @@ -66,6 +67,7 @@ public class KernelWakelockReader { private final String[] mProcWakelocksName = new String[3]; private final long[] mProcWakelocksData = new long[3]; private ISuspendControlService mSuspendControlService = null; + private byte[] mKernelWakelockBuffer = new byte[32 * 1024]; /** * Reads kernel wakelock stats and updates the staleStats with the new information. @@ -84,7 +86,7 @@ public class KernelWakelockReader { } return removeOldStats(staleStats); } else { - byte[] buffer = new byte[32*1024]; + Arrays.fill(mKernelWakelockBuffer, (byte) 0); int len = 0; boolean wakeup_sources; final long startTime = SystemClock.uptimeMillis(); @@ -107,7 +109,8 @@ public class KernelWakelockReader { } int cnt; - while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) { + while ((cnt = is.read(mKernelWakelockBuffer, len, + mKernelWakelockBuffer.length - len)) > 0) { len += cnt; } @@ -125,12 +128,13 @@ public class KernelWakelockReader { } if (len > 0) { - if (len >= buffer.length) { - Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length); + if (len >= mKernelWakelockBuffer.length) { + Slog.wtf(TAG, "Kernel wake locks exceeded mKernelWakelockBuffer size " + + mKernelWakelockBuffer.length); } int i; for (i=0; i<len; i++) { - if (buffer[i] == '\0') { + if (mKernelWakelockBuffer[i] == '\0') { len = i; break; } @@ -143,7 +147,7 @@ public class KernelWakelockReader { Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend"); } // Get kernel wakelock stats - parseProcWakelocks(buffer, len, wakeup_sources, staleStats); + parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats); return removeOldStats(staleStats); } } 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/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 51da0c871c4d..39bf7421b15e 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -611,6 +611,10 @@ public class TransactionParcelTests { } @Override + public void attachStartupAgents(String s) throws RemoteException { + } + + @Override public void scheduleApplicationInfoChanged(ApplicationInfo applicationInfo) throws RemoteException { } 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/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/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java index 618272cbcab0..cfa4065aed62 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -31,15 +32,10 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import android.content.Context; -import android.hardware.display.DisplayManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.SparseArray; -import android.view.Display; -import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -59,7 +55,6 @@ import org.junit.runner.RunWith; public class NavigationBarControllerTest extends SysuiTestCase { private NavigationBarController mNavigationBarController; - private Display mDisplay; private NavigationBarFragment mDefaultNavBar; private NavigationBarFragment mSecondaryNavBar; @@ -89,37 +84,28 @@ public class NavigationBarControllerTest extends SysuiTestCase { @After public void tearDown() { mNavigationBarController = null; - mDisplay = null; mDefaultNavBar = null; mSecondaryNavBar = null; } @Test public void testCreateNavigationBarsIncludeDefaultTrue() { - initializeDisplayManager(); doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); mNavigationBarController.createNavigationBars(true, null); - verify(mNavigationBarController).createNavigationBar(any(Display.class), any()); + verify(mNavigationBarController).createNavigationBar( + argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any()); } @Test public void testCreateNavigationBarsIncludeDefaultFalse() { - initializeDisplayManager(); doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); mNavigationBarController.createNavigationBars(false, null); - verify(mNavigationBarController, never()).createNavigationBar(any(), any()); - } - - private void initializeDisplayManager() { - DisplayManager displayManager = mock(DisplayManager.class); - mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); - Display[] displays = {mDisplay}; - when(displayManager.getDisplays()).thenReturn(displays); - mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager); + verify(mNavigationBarController, never()).createNavigationBar( + argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any()); } // Tests if NPE occurs when call checkNavBarModes() with invalid display. 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/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..4bca7a126418 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5015,7 +5015,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (preBindAgent != null) { thread.attachAgent(preBindAgent); } - + if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + thread.attachStartupAgents(app.info.dataDir); + } // Figure out whether the app needs to run in autofill compat mode. AutofillOptions autofillOptions = null; @@ -18353,7 +18355,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/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 798185ad88f7..6c4cc2d43866 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -65,7 +65,6 @@ import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; -import android.media.AudioAttributes; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -109,6 +108,7 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; @@ -257,6 +257,9 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") private CheckOpsDelegate mCheckOpsDelegate; + @GuardedBy("this") + private SparseArray<List<Integer>> mSwitchOpToOps; + /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -1291,6 +1294,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingOp(code); code = AppOpsManager.opToSwitch(code); + updatePermissionRevokedCompat(uid, code, mode); + synchronized (this) { final int defaultMode = AppOpsManager.opToDefaultMode(code); @@ -1392,6 +1397,86 @@ public class AppOpsService extends IAppOpsService.Stub { notifyOpChangedSync(code, uid, null, mode); } + private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { + PackageManager packageManager = mContext.getPackageManager(); + String[] packageNames = packageManager.getPackagesForUid(uid); + if (ArrayUtils.isEmpty(packageNames)) { + return; + } + String packageName = packageNames[0]; + + List<Integer> ops = getSwitchOpToOps().get(switchCode); + int opsSize = CollectionUtils.size(ops); + for (int i = 0; i < opsSize; i++) { + int code = ops.get(i); + + String permissionName = AppOpsManager.opToPermission(code); + if (permissionName == null) { + continue; + } + + PermissionInfo permissionInfo; + try { + permissionInfo = packageManager.getPermissionInfo(permissionName, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + continue; + } + + if (!permissionInfo.isRuntime()) { + continue; + } + + UserHandle user = UserHandle.getUserHandleForUid(uid); + boolean isRevokedCompat; + if (permissionInfo.backgroundPermission != null) { + boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; + long identity = Binder.clearCallingIdentity(); + try { + packageManager.updatePermissionFlags(permissionInfo.backgroundPermission, + packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, + isBackgroundRevokedCompat + ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); + } finally { + Binder.restoreCallingIdentity(identity); + } + + isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED + && mode != AppOpsManager.MODE_FOREGROUND; + } else { + isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED; + } + + long identity = Binder.clearCallingIdentity(); + try { + packageManager.updatePermissionFlags(permissionName, packageName, + PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat + ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @NonNull + private SparseArray<List<Integer>> getSwitchOpToOps() { + synchronized (this) { + if (mSwitchOpToOps == null) { + mSwitchOpToOps = new SparseArray<>(); + for (int op = 0; op < _NUM_OP; op++) { + int switchOp = AppOpsManager.opToSwitch(op); + List<Integer> ops = mSwitchOpToOps.get(switchOp); + if (ops == null) { + ops = new ArrayList<>(); + mSwitchOpToOps.put(switchOp, ops); + } + ops.add(op); + } + } + return mSwitchOpToOps; + } + } + private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { final StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class); diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java index c46fc20b3cc8..29026e8affcf 100644 --- a/services/core/java/com/android/server/display/ColorFade.java +++ b/services/core/java/com/android/server/display/ColorFade.java @@ -114,6 +114,8 @@ final class ColorFade { private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8); private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8); + private final Transaction mTransaction = new Transaction(); + /** * Animates an color fade warming up. */ @@ -659,14 +661,10 @@ final class ColorFade { private boolean showSurface(float alpha) { if (!mSurfaceVisible || mSurfaceAlpha != alpha) { - SurfaceControl.openTransaction(); - try { - mSurfaceControl.setLayer(COLOR_FADE_LAYER); - mSurfaceControl.setAlpha(alpha); - mSurfaceControl.show(); - } finally { - SurfaceControl.closeTransaction(); - } + mTransaction.setLayer(mSurfaceControl, COLOR_FADE_LAYER) + .setAlpha(mSurfaceControl, alpha) + .show(mSurfaceControl) + .apply(); mSurfaceVisible = true; mSurfaceAlpha = alpha; } 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/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 8facce112b52..976cdfbf8f60 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -23,6 +23,7 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; import static com.android.server.pm.PackageManagerService.fixProcessName; +import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -219,12 +220,14 @@ public class ComponentResolver { } } + @Nullable List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, int userId) { synchronized (mLock) { return mActivities.queryIntent(intent, resolvedType, flags, userId); } } + @Nullable List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, List<PackageParser.Activity> activities, int userId) { synchronized (mLock) { @@ -233,12 +236,14 @@ public class ComponentResolver { } } + @Nullable List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, int userId) { synchronized (mLock) { return mProviders.queryIntent(intent, resolvedType, flags, userId); } } + @Nullable List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, List<PackageParser.Provider> providers, int userId) { synchronized (mLock) { @@ -246,6 +251,7 @@ public class ComponentResolver { } } + @Nullable List<ProviderInfo> queryProviders(String processName, String metaDataKey, int uid, int flags, int userId) { if (!sUserManager.exists(userId)) { @@ -285,6 +291,7 @@ public class ComponentResolver { return providerList; } + @Nullable ProviderInfo queryProvider(String authority, int flags, int userId) { synchronized (mLock) { final PackageParser.Provider p = mProvidersByAuthority.get(authority); @@ -326,12 +333,14 @@ public class ComponentResolver { } } + @Nullable List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, int userId) { synchronized (mLock) { return mReceivers.queryIntent(intent, resolvedType, flags, userId); } } + @Nullable List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, List<PackageParser.Activity> receivers, int userId) { synchronized (mLock) { @@ -339,12 +348,14 @@ public class ComponentResolver { } } + @Nullable List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, int userId) { synchronized (mLock) { return mServices.queryIntent(intent, resolvedType, flags, userId); } } + @Nullable List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, List<PackageParser.Service> services, int userId) { synchronized (mLock) { @@ -1355,6 +1366,7 @@ public class ComponentResolver { return super.queryIntent(intent, resolvedType, defaultOnly, userId); } + @Nullable List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) { @@ -1366,6 +1378,7 @@ public class ComponentResolver { userId); } + @Nullable List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags, List<PackageParser.Provider> packageProviders, int userId) { if (!sUserManager.exists(userId)) { 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..67339c8c8580 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(); @@ -6976,7 +6975,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param intent * @return A filtered list of resolved activities. */ - private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos, + private List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId); @@ -7633,6 +7632,9 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgName == null) { final List<ResolveInfo> result = mComponentResolver.queryReceivers(intent, resolvedType, flags, userId); + if (result == null) { + return Collections.emptyList(); + } return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); @@ -7641,6 +7643,9 @@ public class PackageManagerService extends IPackageManager.Stub if (pkg != null) { final List<ResolveInfo> result = mComponentResolver.queryReceivers( intent, resolvedType, flags, pkg.receivers, userId); + if (result == null) { + return Collections.emptyList(); + } return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); @@ -7735,15 +7740,25 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { String pkgName = intent.getPackage(); if (pkgName == null) { + final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent, + resolvedType, flags, userId); + if (resolveInfos == null) { + return Collections.emptyList(); + } return applyPostServiceResolutionFilter( - mComponentResolver.queryServices(intent, resolvedType, flags, userId), + resolveInfos, instantAppPkgName); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { + final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent, + resolvedType, flags, pkg.services, + userId); + if (resolveInfos == null) { + return Collections.emptyList(); + } return applyPostServiceResolutionFilter( - mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services, - userId), + resolveInfos, instantAppPkgName); } return Collections.emptyList(); @@ -7853,15 +7868,25 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { String pkgName = intent.getPackage(); if (pkgName == null) { + final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent, + resolvedType, flags, userId); + if (resolveInfos == null) { + return Collections.emptyList(); + } return applyPostContentProviderResolutionFilter( - mComponentResolver.queryProviders(intent, resolvedType, flags, userId), + resolveInfos, instantAppPkgName); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { + final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent, + resolvedType, flags, + pkg.providers, userId); + if (resolveInfos == null) { + return Collections.emptyList(); + } return applyPostContentProviderResolutionFilter( - mComponentResolver.queryProviders(intent, resolvedType, flags, - pkg.providers, userId), + resolveInfos, instantAppPkgName); } return Collections.emptyList(); @@ -19652,7 +19677,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 +19784,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 ef31ef151d26..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, diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 59f051bc76a6..10415f58db80 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -271,11 +271,11 @@ final class AccessibilityController { } } - /** NOTE: This has to be called within a surface transaction. */ - public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) { + public void drawMagnifiedRegionBorderIfNeededLocked(int displayId, + SurfaceControl.Transaction t) { final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); if (displayMagnifier != null) { - displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked(); + displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked(t); } // Not relevant for the window observer. } @@ -431,7 +431,7 @@ final class AccessibilityController { Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation) + " displayId: " + displayContent.getDisplayId()); } - mMagnifedViewport.onRotationChangedLocked(); + mMagnifedViewport.onRotationChangedLocked(displayContent.getPendingTransaction()); mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED); } @@ -536,9 +536,8 @@ final class AccessibilityController { .sendToTarget(); } - /** NOTE: This has to be called within a surface transaction. */ - public void drawMagnifiedRegionBorderIfNeededLocked() { - mMagnifedViewport.drawWindowIfNeededLocked(); + public void drawMagnifiedRegionBorderIfNeededLocked(SurfaceControl.Transaction t) { + mMagnifedViewport.drawWindowIfNeededLocked(t); } private final class MagnifiedViewport { @@ -744,7 +743,7 @@ final class AccessibilityController { return letterboxBounds; } - public void onRotationChangedLocked() { + public void onRotationChangedLocked(SurfaceControl.Transaction t) { // If we are showing the magnification border, hide it immediately so // the user does not see strange artifacts during rotation. The screenshot // used for rotation already has the border. After the rotation is complete @@ -758,7 +757,7 @@ final class AccessibilityController { mHandler.sendMessageDelayed(message, delay); } recomputeBoundsLocked(); - mWindow.updateSize(); + mWindow.updateSize(t); } public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) { @@ -784,10 +783,9 @@ final class AccessibilityController { return mMagnificationSpec; } - /** NOTE: This has to be called within a surface transaction. */ - public void drawWindowIfNeededLocked() { + public void drawWindowIfNeededLocked(SurfaceControl.Transaction t) { recomputeBoundsLocked(); - mWindow.drawIfNeeded(); + mWindow.drawIfNeeded(t); } public void destroyWindow() { @@ -837,10 +835,11 @@ final class AccessibilityController { /* ignore */ } mSurfaceControl = surfaceControl; - mSurfaceControl.setLayer(mService.mPolicy.getWindowLayerFromTypeLw( - TYPE_MAGNIFICATION_OVERLAY) - * WindowManagerService.TYPE_LAYER_MULTIPLIER); - mSurfaceControl.setPosition(0, 0); + mService.mTransactionFactory.get().setLayer(mSurfaceControl, + mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) + * WindowManagerService.TYPE_LAYER_MULTIPLIER) + .setPosition(mSurfaceControl, 0, 0) + .apply(); mSurface.copyFrom(mSurfaceControl); mAnimationController = new AnimationController(context, @@ -905,10 +904,10 @@ final class AccessibilityController { } } - public void updateSize() { + public void updateSize(SurfaceControl.Transaction t) { synchronized (mService.mGlobalLock) { mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); - mSurfaceControl.setBufferSize(mTempPoint.x, mTempPoint.y); + t.setBufferSize(mSurfaceControl, mTempPoint.x, mTempPoint.y); invalidate(mDirtyRect); } } @@ -923,8 +922,7 @@ final class AccessibilityController { mService.scheduleAnimationLocked(); } - /** NOTE: This has to be called within a surface transaction. */ - public void drawIfNeeded() { + public void drawIfNeeded(SurfaceControl.Transaction t) { synchronized (mService.mGlobalLock) { if (!mInvalidated) { return; @@ -959,9 +957,9 @@ final class AccessibilityController { canvas.drawPath(path, mPaint); mSurface.unlockCanvasAndPost(canvas); - mSurfaceControl.show(); + t.show(mSurfaceControl); } else { - mSurfaceControl.hide(); + t.hide(mSurfaceControl); } } } 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/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index b1ef60185d8d..a261341cfa53 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2930,7 +2930,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree layer += Z_BOOST_BASE; } if (!mNeedsAnimationBoundsLayer) { - leash.setLayer(layer); + t.setLayer(leash, layer); } final DisplayContent dc = getDisplayContent(); diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java index c1ca816d788a..b73b481075ae 100644 --- a/services/core/java/com/android/server/wm/CircularDisplayMask.java +++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java @@ -56,7 +56,7 @@ class CircularDisplayMask { private int mMaskThickness; CircularDisplayMask(Supplier<Surface> surfaceFactory, DisplayContent dc, int zOrder, - int screenOffset, int maskThickness) { + int screenOffset, int maskThickness, SurfaceControl.Transaction t) { final Display display = dc.getDisplay(); mSurface = surfaceFactory.get(); mScreenSize = new Point(); @@ -75,10 +75,10 @@ class CircularDisplayMask { .setFormat(PixelFormat.TRANSLUCENT) .build(); - ctrl.setLayerStack(display.getLayerStack()); - ctrl.setLayer(zOrder); - ctrl.setPosition(0, 0); - ctrl.show(); + t.setLayerStack(ctrl, display.getLayerStack()); + t.setLayer(ctrl, zOrder); + t.setPosition(ctrl, 0, 0); + t.show(ctrl); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } @@ -91,7 +91,7 @@ class CircularDisplayMask { mMaskThickness = maskThickness; } - private void drawIfNeeded() { + private void drawIfNeeded(SurfaceControl.Transaction t) { if (!mDrawNeeded || !mVisible || mDimensionsUnequal) { return; } @@ -108,45 +108,46 @@ class CircularDisplayMask { return; } switch (mRotation) { - case Surface.ROTATION_0: - case Surface.ROTATION_90: - // chin bottom or right - mSurfaceControl.setPosition(0, 0); - break; - case Surface.ROTATION_180: - // chin top - mSurfaceControl.setPosition(0, -mScreenOffset); - break; - case Surface.ROTATION_270: - // chin left - mSurfaceControl.setPosition(-mScreenOffset, 0); - break; + case Surface.ROTATION_0: + case Surface.ROTATION_90: + // chin bottom or right + t.setPosition(mSurfaceControl, 0, 0); + break; + case Surface.ROTATION_180: + // chin top + t.setPosition(mSurfaceControl, 0, -mScreenOffset); + break; + case Surface.ROTATION_270: + // chin left + t.setPosition(mSurfaceControl, -mScreenOffset, 0); + break; } int circleRadius = mScreenSize.x / 2; c.drawColor(Color.BLACK); - // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the display edges. + // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the + // display edges. c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint); mSurface.unlockCanvasAndPost(c); } // Note: caller responsible for being inside // Surface.openTransaction() / closeTransaction() - public void setVisibility(boolean on) { + public void setVisibility(boolean on, SurfaceControl.Transaction t) { if (mSurfaceControl == null) { return; } mVisible = on; - drawIfNeeded(); + drawIfNeeded(t); if (on) { - mSurfaceControl.show(); + t.show(mSurfaceControl); } else { - mSurfaceControl.hide(); + t.hide(mSurfaceControl); } } - void positionSurface(int dw, int dh, int rotation) { + void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) { if (mLastDW == dw && mLastDH == dh && mRotation == rotation) { return; } @@ -154,7 +155,7 @@ class CircularDisplayMask { mLastDH = dh; mDrawNeeded = true; mRotation = rotation; - drawIfNeeded(); + drawIfNeeded(t); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f592ac6957cb..ac910cde79b0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -331,7 +331,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** * For default display it contains real metrics, empty for others. - * @see WindowManagerService#createWatermarkInTransaction() + * @see WindowManagerService#createWatermark() */ final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics(); diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java index f64592fd46bd..2165b0e8b593 100644 --- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java +++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java @@ -50,7 +50,7 @@ class EmulatorDisplayOverlay { private boolean mVisible; EmulatorDisplayOverlay(Supplier<Surface> surfaceFactory, Context context, DisplayContent dc, - int zOrder) { + int zOrder, SurfaceControl.Transaction t) { mSurface = surfaceFactory.get(); final Display display = dc.getDisplay(); mScreenSize = new Point(); @@ -63,9 +63,9 @@ class EmulatorDisplayOverlay { .setBufferSize(mScreenSize.x, mScreenSize.y) .setFormat(PixelFormat.TRANSLUCENT) .build(); - ctrl.setLayer(zOrder); - ctrl.setPosition(0, 0); - ctrl.show(); + t.setLayer(ctrl, zOrder); + t.setPosition(ctrl, 0, 0); + t.show(ctrl); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } @@ -75,7 +75,7 @@ class EmulatorDisplayOverlay { com.android.internal.R.drawable.emulator_circular_window_overlay); } - private void drawIfNeeded() { + private void drawIfNeeded(SurfaceControl.Transaction t) { if (!mDrawNeeded || !mVisible) { return; } @@ -92,7 +92,7 @@ class EmulatorDisplayOverlay { return; } c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC); - mSurfaceControl.setPosition(0, 0); + t.setPosition(mSurfaceControl, 0, 0); // Always draw the overlay with square dimensions int size = Math.max(mScreenSize.x, mScreenSize.y); mOverlay.setBounds(0, 0, size, size); @@ -102,20 +102,20 @@ class EmulatorDisplayOverlay { // Note: caller responsible for being inside // Surface.openTransaction() / closeTransaction() - public void setVisibility(boolean on) { + public void setVisibility(boolean on, SurfaceControl.Transaction t) { if (mSurfaceControl == null) { return; } mVisible = on; - drawIfNeeded(); + drawIfNeeded(t); if (on) { - mSurfaceControl.show(); + t.show(mSurfaceControl); } else { - mSurfaceControl.hide(); + t.hide(mSurfaceControl); } } - void positionSurface(int dw, int dh, int rotation) { + void positionSurface(int dw, int dh, int rotation, SurfaceControl.Transaction t) { if (mLastDW == dw && mLastDH == dh && mRotation == rotation) { return; } @@ -123,7 +123,7 @@ class EmulatorDisplayOverlay { mLastDH = dh; mDrawNeeded = true; mRotation = rotation; - drawIfNeeded(); + drawIfNeeded(t); } } 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/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 1bd2493e9a07..94d010e846f5 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -247,12 +247,12 @@ public class Letterbox { mLayoutFrameRelative.offset(-surfaceOrigin.x, -surfaceOrigin.y); } - private void createSurface() { + private void createSurface(SurfaceControl.Transaction t) { mSurface = mSurfaceControlFactory.get().setName("Letterbox - " + mType) .setFlags(HIDDEN).setColorLayer().build(); - mSurface.setLayer(-1); - mSurface.setColor(new float[]{0, 0, 0}); - mSurface.setColorSpaceAgnostic(true); + t.setLayer(mSurface, -1) + .setColor(mSurface, new float[]{0, 0, 0}) + .setColorSpaceAgnostic(mSurface, true); } void attachInput(WindowState win) { @@ -300,7 +300,7 @@ public class Letterbox { mSurfaceFrameRelative.set(mLayoutFrameRelative); if (!mSurfaceFrameRelative.isEmpty()) { if (mSurface == null) { - createSurface(); + createSurface(t); } t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top); t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(), diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6f10d3d291b1..b6a05d1b9608 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -813,18 +813,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int defaultDw = defaultInfo.logicalWidth; final int defaultDh = defaultInfo.logicalHeight; if (mWmService.mWatermark != null) { - mWmService.mWatermark.positionSurface(defaultDw, defaultDh); + mWmService.mWatermark.positionSurface(defaultDw, defaultDh, mDisplayTransaction); } if (mWmService.mStrictModeFlash != null) { - mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh); + mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, mDisplayTransaction); } if (mWmService.mCircularDisplayMask != null) { mWmService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh, - mWmService.getDefaultDisplayRotation()); + mWmService.getDefaultDisplayRotation(), mDisplayTransaction); } if (mWmService.mEmulatorDisplayOverlay != null) { mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh, - mWmService.getDefaultDisplayRotation()); + mWmService.getDefaultDisplayRotation(), mDisplayTransaction); } final int count = mChildren.size(); diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java index bcd90a14ac96..ba31818d6331 100644 --- a/services/core/java/com/android/server/wm/SeamlessRotator.java +++ b/services/core/java/com/android/server/wm/SeamlessRotator.java @@ -20,9 +20,10 @@ import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.graphics.Matrix; +import android.os.IBinder; import android.view.DisplayInfo; -import android.view.Surface; import android.view.Surface.Rotation; +import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.server.wm.utils.CoordinateTransforms; @@ -35,7 +36,7 @@ import java.io.StringWriter; * * Works by transforming the {@link WindowState} back into the old display rotation. * - * Uses {@link android.view.SurfaceControl#deferTransactionUntil(Surface, long)} instead of + * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of * latching on the buffer size to allow for seamless 180 degree rotations. */ public class SeamlessRotator { diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java index 9e5d9cab7669..f537005c955c 100644 --- a/services/core/java/com/android/server/wm/StrictModeFlash.java +++ b/services/core/java/com/android/server/wm/StrictModeFlash.java @@ -39,7 +39,8 @@ class StrictModeFlash { private boolean mDrawNeeded; private final int mThickness = 20; - StrictModeFlash(Supplier<Surface> surfaceFactory, DisplayContent dc) { + StrictModeFlash(Supplier<Surface> surfaceFactory, DisplayContent dc, + SurfaceControl.Transaction t) { mSurface = surfaceFactory.get(); SurfaceControl ctrl = null; try { @@ -48,9 +49,11 @@ class StrictModeFlash { .setBufferSize(1, 1) .setFormat(PixelFormat.TRANSLUCENT) .build(); - ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 101); // one more than Watermark? arbitrary. - ctrl.setPosition(0, 0); - ctrl.show(); + + // one more than Watermark? arbitrary. + t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101); + t.setPosition(ctrl, 0, 0); + t.show(ctrl); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } @@ -103,25 +106,25 @@ class StrictModeFlash { // Note: caller responsible for being inside // Surface.openTransaction() / closeTransaction() - public void setVisibility(boolean on) { + public void setVisibility(boolean on, SurfaceControl.Transaction t) { if (mSurfaceControl == null) { return; } drawIfNeeded(); if (on) { - mSurfaceControl.show(); + t.show(mSurfaceControl); } else { - mSurfaceControl.hide(); + t.hide(mSurfaceControl); } } - void positionSurface(int dw, int dh) { + void positionSurface(int dw, int dh, SurfaceControl.Transaction t) { if (mLastDW == dw && mLastDH == dh) { return; } mLastDW = dw; mLastDH = dh; - mSurfaceControl.setBufferSize(dw, dh); + t.setBufferSize(mSurfaceControl, dw, dh); mDrawNeeded = true; } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index d070850a895f..172ebce33668 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -134,6 +134,7 @@ class TaskSnapshotSurface implements StartingSurface { private final int mStatusBarColor; @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter; private final int mOrientationOnCreation; + private final SurfaceControl.Transaction mTransaction; static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token, TaskSnapshot snapshot) { @@ -252,6 +253,7 @@ class TaskSnapshotSurface implements StartingSurface { windowPrivateFlags, sysUiVis, taskDescription, 1f); mStatusBarColor = taskDescription.getStatusBarColor(); mOrientationOnCreation = currentOrientation; + mTransaction = mService.mTransactionFactory.get(); } @Override @@ -336,27 +338,23 @@ class TaskSnapshotSurface implements StartingSurface { surface.copyFrom(mChildSurfaceControl); final Rect frame; - SurfaceControl.openTransaction(); - try { - // We can just show the surface here as it will still be hidden as the parent is - // still hidden. - mChildSurfaceControl.show(); - if (aspectRatioMismatch) { - // Clip off ugly navigation bar. - final Rect crop = calculateSnapshotCrop(); - frame = calculateSnapshotFrame(crop); - mChildSurfaceControl.setWindowCrop(crop); - mChildSurfaceControl.setPosition(frame.left, frame.top); - } else { - frame = null; - } - - // Scale the mismatch dimensions to fill the task bounds - final float scale = 1 / mSnapshot.getScale(); - mChildSurfaceControl.setMatrix(scale, 0, 0, scale); - } finally { - SurfaceControl.closeTransaction(); + // We can just show the surface here as it will still be hidden as the parent is + // still hidden. + mTransaction.show(mChildSurfaceControl); + if (aspectRatioMismatch) { + // Clip off ugly navigation bar. + final Rect crop = calculateSnapshotCrop(); + frame = calculateSnapshotFrame(crop); + mTransaction.setWindowCrop(mChildSurfaceControl, crop); + mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top); + } else { + frame = null; } + + // Scale the mismatch dimensions to fill the task bounds + final float scale = 1 / mSnapshot.getScale(); + mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale); + mTransaction.apply(); surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace()); surface.release(); diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java index 729cfc04e36c..725aaa48c645 100644 --- a/services/core/java/com/android/server/wm/Watermark.java +++ b/services/core/java/com/android/server/wm/Watermark.java @@ -55,7 +55,7 @@ class Watermark { private boolean mDrawNeeded; Watermark(Supplier<Surface> surfaceFactory, DisplayContent dc, DisplayMetrics dm, - String[] tokens) { + String[] tokens, SurfaceControl.Transaction t) { if (false) { Log.i(TAG_WM, "*********************** WATERMARK"); for (int i=0; i<tokens.length; i++) { @@ -121,21 +121,21 @@ class Watermark { .setBufferSize(1, 1) .setFormat(PixelFormat.TRANSLUCENT) .build(); - ctrl.setLayerStack(mDisplay.getLayerStack()); - ctrl.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100); - ctrl.setPosition(0, 0); - ctrl.show(); + t.setLayerStack(ctrl, mDisplay.getLayerStack()) + .setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100) + .setPosition(ctrl, 0, 0) + .show(ctrl); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } mSurfaceControl = ctrl; } - void positionSurface(int dw, int dh) { + void positionSurface(int dw, int dh, SurfaceControl.Transaction t) { if (mLastDW != dw || mLastDH != dh) { mLastDW = dw; mLastDH = dh; - mSurfaceControl.setBufferSize(dw, dh); + t.setBufferSize(mSurfaceControl, dw, dh); mDrawNeeded = true; } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index f437b284637b..3a1d6e047fa8 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -161,7 +161,8 @@ public class WindowAnimator { dc.checkAppWindowsReadyToShow(); orAnimating(dc.getDockedDividerController().animate(mCurrentTime)); if (accessibilityController != null) { - accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId); + accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId, + mTransaction); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0f4d0a8662f4..6f9f2c0f9708 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1269,14 +1269,7 @@ public class WindowManagerService extends IWindowManager.Stub // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); - - openSurfaceTransaction(); - try { - createWatermarkInTransaction(); - } finally { - closeSurfaceTransaction("createWatermarkInTransaction"); - } - + createWatermark(); showEmulatorDisplayOverlayIfNeeded(); } @@ -3435,60 +3428,45 @@ public class WindowManagerService extends IWindowManager.Stub public void showCircularMask(boolean visible) { synchronized (mGlobalLock) { + if (visible) { + // TODO(multi-display): support multiple displays + if (mCircularDisplayMask == null) { + int screenOffset = mContext.getResources().getInteger( + com.android.internal.R.integer.config_windowOutsetBottom); + int maskThickness = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.circular_display_mask_thickness); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - ">>> OPEN TRANSACTION showCircularMask(visible=" + visible + ")"); - openSurfaceTransaction(); - try { - if (visible) { - // TODO(multi-display): support multiple displays - if (mCircularDisplayMask == null) { - int screenOffset = mContext.getResources().getInteger( - com.android.internal.R.integer.config_windowOutsetBottom); - int maskThickness = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.circular_display_mask_thickness); - - mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory, - getDefaultDisplayContentLocked(), - mPolicy.getWindowLayerFromTypeLw( - WindowManager.LayoutParams.TYPE_POINTER) - * TYPE_LAYER_MULTIPLIER + 10, screenOffset, maskThickness); + + if (SHOW_LIGHT_TRANSACTIONS) { + Slog.i(TAG_WM, + ">>> showCircularMask(visible=" + visible + ")"); } - mCircularDisplayMask.setVisibility(true); - } else if (mCircularDisplayMask != null) { - mCircularDisplayMask.setVisibility(false); - mCircularDisplayMask = null; + mCircularDisplayMask = new CircularDisplayMask(mSurfaceFactory, + getDefaultDisplayContentLocked(), mPolicy.getWindowLayerFromTypeLw( + WindowManager.LayoutParams.TYPE_POINTER) * TYPE_LAYER_MULTIPLIER + + 10, screenOffset, maskThickness, mTransaction); } - } finally { - closeSurfaceTransaction("showCircularMask"); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - "<<< CLOSE TRANSACTION showCircularMask(visible=" + visible + ")"); + mCircularDisplayMask.setVisibility(true, mTransaction); + } else if (mCircularDisplayMask != null) { + mCircularDisplayMask.setVisibility(false, mTransaction); + mCircularDisplayMask = null; } + mTransaction.apply(); } } public void showEmulatorDisplayOverlay() { synchronized (mGlobalLock) { - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - ">>> OPEN TRANSACTION showEmulatorDisplayOverlay"); - openSurfaceTransaction(); - try { - if (mEmulatorDisplayOverlay == null) { - mEmulatorDisplayOverlay = new EmulatorDisplayOverlay( - mSurfaceFactory, - mContext, - getDefaultDisplayContentLocked(), - mPolicy.getWindowLayerFromTypeLw( - WindowManager.LayoutParams.TYPE_POINTER) - * TYPE_LAYER_MULTIPLIER + 10); - } - mEmulatorDisplayOverlay.setVisibility(true); - } finally { - closeSurfaceTransaction("showEmulatorDisplayOverlay"); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, - "<<< CLOSE TRANSACTION showEmulatorDisplayOverlay"); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> showEmulatorDisplayOverlay"); + if (mEmulatorDisplayOverlay == null) { + mEmulatorDisplayOverlay = new EmulatorDisplayOverlay(mSurfaceFactory, mContext, + getDefaultDisplayContentLocked(), + mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_POINTER) + * TYPE_LAYER_MULTIPLIER + 10, mTransaction); } + mEmulatorDisplayOverlay.setVisibility(true, mTransaction); + mTransaction.apply(); } } @@ -3517,23 +3495,16 @@ public class WindowManagerService extends IWindowManager.Stub return; } - if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, - ">>> OPEN TRANSACTION showStrictModeViolation"); + if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, ">>> showStrictModeViolation"); // TODO: Modify this to use the surface trace once it is not going crazy. // b/31532461 - SurfaceControl.openTransaction(); - try { - // TODO(multi-display): support multiple displays - if (mStrictModeFlash == null) { - mStrictModeFlash = new StrictModeFlash(mSurfaceFactory, - getDefaultDisplayContentLocked()); - } - mStrictModeFlash.setVisibility(on); - } finally { - SurfaceControl.closeTransaction(); - if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, - "<<< CLOSE TRANSACTION showStrictModeViolation"); + // TODO(multi-display): support multiple displays + if (mStrictModeFlash == null) { + mStrictModeFlash = new StrictModeFlash(mSurfaceFactory, + getDefaultDisplayContentLocked(), mTransaction); } + mStrictModeFlash.setVisibility(on, mTransaction); + mTransaction.apply(); } } @@ -5520,7 +5491,7 @@ public class WindowManagerService extends IWindowManager.Stub return val; } - void createWatermarkInTransaction() { + void createWatermark() { if (mWatermark != null) { return; } @@ -5538,8 +5509,8 @@ public class WindowManagerService extends IWindowManager.Stub // TODO(multi-display): Show watermarks on secondary displays. final DisplayContent displayContent = getDefaultDisplayContentLocked(); mWatermark = new Watermark(mSurfaceFactory, displayContent, - displayContent.mRealDisplayMetrics, - toks); + displayContent.mRealDisplayMetrics, toks, mTransaction); + mTransaction.apply(); } } } catch (FileNotFoundException e) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 3dcf6ecb5124..1328273c9560 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -506,9 +506,8 @@ class WindowStateAnimator { flags |= SurfaceControl.OPAQUE; } - mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession, - attrs.getTitle().toString(), width, height, format, flags, this, - windowType, ownerUid); + mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), width, + height, format, flags, this, windowType, ownerUid); mSurfaceController.setColorSpaceAgnostic((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0); diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 49f27a1b495d..7f68c48e473f 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -37,7 +37,6 @@ import android.os.Trace; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; -import android.view.SurfaceSession; import android.view.WindowContentFrameStats; import com.android.server.protolog.common.ProtoLog; @@ -85,7 +84,7 @@ class WindowSurfaceController { private final SurfaceControl.Transaction mTmpTransaction; - public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format, + WindowSurfaceController(String name, int w, int h, int format, int flags, WindowStateAnimator animator, int windowType, int ownerUid) { mAnimator = animator; 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/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index a98f79cb5369..73420a095cad 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -46,7 +46,7 @@ public class DimmerTests extends WindowTestsBase { private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { final SurfaceControl mControl = mock(SurfaceControl.class); - final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction mTransaction = spy(StubTransaction.class); TestWindowContainer(WindowManagerService wm) { super(wm); @@ -66,7 +66,7 @@ public class DimmerTests extends WindowTestsBase { private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> { final SurfaceSession mSession = new SurfaceSession(); final SurfaceControl mHostControl = mock(SurfaceControl.class); - final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction mHostTransaction = spy(StubTransaction.class); MockSurfaceBuildingContainer(WindowManagerService wm) { super(wm); @@ -118,7 +118,7 @@ public class DimmerTests extends WindowTestsBase { public void setUp() throws Exception { mHost = new MockSurfaceBuildingContainer(mWm); mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl()); - mTransaction = mock(SurfaceControl.Transaction.class); + mTransaction = spy(StubTransaction.class); mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter); } 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/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index 2d0416d6f5bc..15417d73bd02 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,8 +49,8 @@ public class LetterboxTest { @Before public void setUp() throws Exception { mSurfaces = new SurfaceControlMocker(); - mLetterbox = new Letterbox(mSurfaces, () -> mock(SurfaceControl.Transaction.class)); - mTransaction = mock(SurfaceControl.Transaction.class); + mLetterbox = new Letterbox(mSurfaces, StubTransaction::new); + mTransaction = spy(StubTransaction.class); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index 2ad40f2dc577..f5d08dcfcb77 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -239,4 +239,15 @@ public class StubTransaction extends SurfaceControl.Transaction { public SurfaceControl.Transaction remove(SurfaceControl sc) { return this; } + + @Override + public SurfaceControl.Transaction syncInputWindows() { + return this; + } + + @Override + public SurfaceControl.Transaction setColorSpaceAgnostic(SurfaceControl sc, boolean agnostic) { + return this; + } + } 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/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java index 0330de8d2c63..bfc07419fd46 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.graphics.Point; @@ -50,7 +51,7 @@ import org.junit.Test; @Presubmit public class WindowAnimationSpecTest { private final SurfaceControl mSurfaceControl = mock(SurfaceControl.class); - private final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class); + private final SurfaceControl.Transaction mTransaction = spy(StubTransaction.class); private final Animation mAnimation = mock(Animation.class); private final Rect mStackBounds = new Rect(0, 0, 10, 10); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index e5fb28d51fed..a09253ab31f0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -452,7 +452,7 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testSeamlesslyRotateWindow() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction t = spy(StubTransaction.class); app.mHasSurface = true; app.mSurfaceControl = mock(SurfaceControl.class); @@ -536,7 +536,7 @@ public class WindowStateTests extends WindowTestsBase { final float[] values = new float[9]; final Matrix matrix = new Matrix(); - final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction t = spy(StubTransaction.class); final WindowState win1 = createWindow(null, TYPE_APPLICATION, dc, "win1"); win1.mHasSurface = true; win1.mSurfaceControl = mock(SurfaceControl.class); diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index f4eae8ef4b2a..f4eae8ef4b2a 100644 --- a/telephony/java/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 432978d1c866..b7dab161c331 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -35,6 +35,15 @@ public abstract class CellIdentity implements Parcelable { /** @hide */ public static final int INVALID_CHANNEL_NUMBER = -1; + /** + * parameters for validation + * @hide + */ + public static final int MCC_LENGTH = 3; + + private static final int MNC_MIN_LENGTH = 2; + private static final int MNC_MAX_LENGTH = 3; + // Log tag /** @hide */ protected final String mTag; @@ -207,6 +216,17 @@ public abstract class CellIdentity implements Parcelable { dest.writeString(mAlphaShort); } + /** Used by phone interface manager to verify if a given string is valid MccMnc + * @hide + */ + public static boolean isValidPlmn(@NonNull String plmn) { + if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH + || plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) { + return false; + } + return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH))); + } + /** * Construct from Parcel * @hide @@ -267,10 +287,10 @@ public abstract class CellIdentity implements Parcelable { /** @hide */ private static boolean isMcc(@NonNull String mcc) { // ensure no out of bounds indexing - if (mcc.length() != 3) return false; + if (mcc.length() != MCC_LENGTH) return false; // Character.isDigit allows all unicode digits, not just [0-9] - for (int i = 0; i < 3; i++) { + for (int i = 0; i < MCC_LENGTH; i++) { if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false; } @@ -280,7 +300,7 @@ public abstract class CellIdentity implements Parcelable { /** @hide */ private static boolean isMnc(@NonNull String mnc) { // ensure no out of bounds indexing - if (mnc.length() < 2 || mnc.length() > 3) return false; + if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false; // Character.isDigit allows all unicode digits, not just [0-9] for (int i = 0; i < mnc.length(); i++) { @@ -289,4 +309,5 @@ public abstract class CellIdentity implements Parcelable { return true; } + } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 66571e39394e..2442023ee27c 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -6852,6 +6852,40 @@ public class TelephonyManager { } /** + * Replace the contents of the forbidden PLMN SIM file with the provided values. + * Passing an empty list will clear the contents of the EFfplmn file. + * If the provided list is shorter than the size of EFfplmn, then the list will be padded + * up to the file size with 'FFFFFF'. (required by 3GPP TS 31.102 spec 4.2.16) + * If the list is longer than the size of EFfplmn, then the file will be written from the + * beginning of the list up to the file size. + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * + * @param fplmns a list of PLMNs to be forbidden. + * + * @return number of PLMNs that were successfully written to the SIM FPLMN list. + * This may be less than the number of PLMNs passed in where the SIM file does not have enough + * room for all of the values passed in. Return -1 in the event of an unexpected failure + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public int setForbiddenPlmns(@NonNull List<String> fplmns) { + try { + ITelephony telephony = getITelephony(); + if (telephony == null) return 0; + return telephony.setForbiddenPlmns( + getSubId(), APPTYPE_USIM, fplmns, getOpPackageName()); + } catch (RemoteException ex) { + Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage()); + } catch (NullPointerException ex) { + // This could happen before phone starts + Rlog.e(TAG, "setForbiddenPlmns NullPointerException: " + ex.getMessage()); + } + return 0; + } + + /** * Get P-CSCF address from PCO after data connection is established or modified. * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN * @return array of P-CSCF address 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/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index cabd4dfd91f1..5a90cb13a548 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.TelephonyManager; +import android.telephony.euicc.EuiccCardManager.ResetOption; import com.android.internal.telephony.euicc.IEuiccController; @@ -821,17 +822,22 @@ public class EuiccManager { } /** - * Erase all subscriptions and reset the eUICC. + * Erase all operational subscriptions and reset the eUICC. * * <p>Requires that the calling app has the * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. * * @param callbackIntent a PendingIntent to launch when the operation completes. + * + * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase + * and use @link{eraseSubscriptionsWithOptions} instead + * * @hide */ @SystemApi @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) - public void eraseSubscriptions(PendingIntent callbackIntent) { + @Deprecated + public void eraseSubscriptions(@NonNull PendingIntent callbackIntent) { if (!isEnabled()) { sendUnavailableError(callbackIntent); return; @@ -844,6 +850,32 @@ public class EuiccManager { } /** + * Erase all specific subscriptions and reset the eUICC. + * + * <p>Requires that the calling app has the + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. + * + * @param options flag indicating specific set of subscriptions to erase + * @param callbackIntent a PendingIntent to launch when the operation completes. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) + public void eraseSubscriptionsWithOptions( + @ResetOption int options, @NonNull PendingIntent callbackIntent) { + if (!isEnabled()) { + sendUnavailableError(callbackIntent); + return; + } + try { + getIEuiccController().eraseSubscriptionsWithOptions(mCardId, options, callbackIntent); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Ensure that subscriptions will be retained on the next factory reset. * * <p>By default, all subscriptions on the eUICC are erased the first time a device boots (ever diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 4d9057975727..fd7ec561faef 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1612,6 +1612,18 @@ interface ITelephony { String[] getForbiddenPlmns(int subId, int appType, String callingPackage); /** + * Set the forbidden PLMN list from the givven app type (ex APPTYPE_USIM) on a particular + * subscription. + * + * @param subId subId the id of the subscription + * @param appType appType the uicc app type, must be USIM or SIM. + * @param fplmns plmns the Forbiden plmns list that needed to be written to the SIM. + * @param content callingPackage the op Package name. + * @return number of fplmns that is successfully written to the SIM + */ + int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage); + + /** * Check if phone is in emergency callback mode * @return true if phone is in emergency callback mode * @param subId the subscription ID that this action applies to. 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/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index 20169152539e..7422863d862c 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -44,5 +44,7 @@ interface IEuiccController { oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname, String callingPackage, in PendingIntent callbackIntent); oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent); + oneway void eraseSubscriptionsWithOptions( + int cardId, int options, in PendingIntent callbackIntent); oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent); } diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java index 9c69e2d6e08f..f2d46244d60e 100644 --- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java @@ -22,11 +22,13 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.telephony.Rlog; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet; import dalvik.annotation.compat.UnsupportedAppUsage; import java.io.UnsupportedEncodingException; +import java.util.List; /** * Various methods, useful for dealing with SIM data. @@ -34,6 +36,11 @@ import java.io.UnsupportedEncodingException; public class IccUtils { static final String LOG_TAG="IccUtils"; + // 3GPP specification constants + // Spec reference TS 31.102 section 4.2.16 + @VisibleForTesting + static final int FPLMN_BYTE_SIZE = 3; + // A table mapping from a number to a hex character for fast encoding hex strings. private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' @@ -896,4 +903,27 @@ public class IccUtils { } return 0; } + + /** + * Encode the Fplmns into byte array to write to EF. + * + * @param fplmns Array of fplmns to be serialized. + * @param dataLength the size of the EF file. + * @return the encoded byte array in the correct format for FPLMN file. + */ + public static byte[] encodeFplmns(List<String> fplmns, int dataLength) { + byte[] serializedFplmns = new byte[dataLength]; + int offset = 0; + for (String fplmn : fplmns) { + if (offset >= dataLength) break; + stringToBcdPlmn(fplmn, serializedFplmns, offset); + offset += FPLMN_BYTE_SIZE; + } + //pads to the length of the EF file. + while (offset < dataLength) { + // required by 3GPP TS 31.102 spec 4.2.16 + serializedFplmns[offset++] = (byte) 0xff; + } + return serializedFplmns; + } } 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; |