Merge "Allow recents animation controller to control input consumer lifecycle"
diff --git a/Android.mk b/Android.mk
index ba153ee..770ec20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -113,6 +113,17 @@
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA): \
+ frameworks/base/tools/hiddenapi/merge_csv.py \
+ $(PRIVATE_METADATA_INPUTS)
+ frameworks/base/tools/hiddenapi/merge_csv.py $(PRIVATE_METADATA_INPUTS) > $@
+
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA))
+
# Include subdirectory makefiles
# ============================================================
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ff40f75..5c21221 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@
packages/PrintRecommendationService/
packages/PrintSpooler/
packages/PackageInstaller/
+ packages/SystemUI/
services/print/
services/usb/
telephony/
diff --git a/api/current.txt b/api/current.txt
index 71793c0..bb4c98d5 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -29722,6 +29722,65 @@
field public static final int EGL_WINDOW_BIT = 4; // 0x4
}
+ public class EGL15 {
+ ctor public EGL15();
+ method public static int eglClientWaitSync(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long);
+ method public static android.opengl.EGLSurface eglCreatePlatformPixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
+ method public static android.opengl.EGLSurface eglCreatePlatformWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
+ method public static android.opengl.EGLSync eglCreateSync(android.opengl.EGLDisplay, int, long[], int);
+ method public static boolean eglDestroySync(android.opengl.EGLDisplay, android.opengl.EGLSync);
+ method public static android.opengl.EGLDisplay eglGetPlatformDisplay(int, long, long[], int);
+ method public static boolean eglGetSyncAttrib(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long[], int);
+ method public static boolean eglWaitSync(android.opengl.EGLDisplay, android.opengl.EGLSync, int);
+ field public static final int EGL_CL_EVENT_HANDLE = 12444; // 0x309c
+ field public static final int EGL_CONDITION_SATISFIED = 12534; // 0x30f6
+ field public static final int EGL_CONTEXT_MAJOR_VERSION = 12440; // 0x3098
+ field public static final int EGL_CONTEXT_MINOR_VERSION = 12539; // 0x30fb
+ field public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 2; // 0x2
+ field public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 1; // 0x1
+ field public static final int EGL_CONTEXT_OPENGL_DEBUG = 12720; // 0x31b0
+ field public static final int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 12721; // 0x31b1
+ field public static final int EGL_CONTEXT_OPENGL_PROFILE_MASK = 12541; // 0x30fd
+ field public static final int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 12733; // 0x31bd
+ field public static final int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 12722; // 0x31b2
+ field public static final long EGL_FOREVER = -1L; // 0xffffffffffffffffL
+ field public static final int EGL_GL_COLORSPACE = 12445; // 0x309d
+ field public static final int EGL_GL_COLORSPACE_LINEAR = 12426; // 0x308a
+ field public static final int EGL_GL_COLORSPACE_SRGB = 12425; // 0x3089
+ field public static final int EGL_GL_RENDERBUFFER = 12473; // 0x30b9
+ field public static final int EGL_GL_TEXTURE_2D = 12465; // 0x30b1
+ field public static final int EGL_GL_TEXTURE_3D = 12466; // 0x30b2
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 12468; // 0x30b4
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 12470; // 0x30b6
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 12472; // 0x30b8
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 12467; // 0x30b3
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 12469; // 0x30b5
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 12471; // 0x30b7
+ field public static final int EGL_GL_TEXTURE_LEVEL = 12476; // 0x30bc
+ field public static final int EGL_GL_TEXTURE_ZOFFSET = 12477; // 0x30bd
+ field public static final int EGL_IMAGE_PRESERVED = 12498; // 0x30d2
+ field public static final int EGL_LOSE_CONTEXT_ON_RESET = 12735; // 0x31bf
+ field public static final android.opengl.EGLContext EGL_NO_CONTEXT;
+ field public static final android.opengl.EGLDisplay EGL_NO_DISPLAY;
+ field public static final android.opengl.EGLImage EGL_NO_IMAGE;
+ field public static final int EGL_NO_RESET_NOTIFICATION = 12734; // 0x31be
+ field public static final android.opengl.EGLSurface EGL_NO_SURFACE;
+ field public static final android.opengl.EGLSync EGL_NO_SYNC;
+ field public static final int EGL_OPENGL_ES3_BIT = 64; // 0x40
+ field public static final int EGL_PLATFORM_ANDROID_KHR = 12609; // 0x3141
+ field public static final int EGL_SIGNALED = 12530; // 0x30f2
+ field public static final int EGL_SYNC_CL_EVENT = 12542; // 0x30fe
+ field public static final int EGL_SYNC_CL_EVENT_COMPLETE = 12543; // 0x30ff
+ field public static final int EGL_SYNC_CONDITION = 12536; // 0x30f8
+ field public static final int EGL_SYNC_FENCE = 12537; // 0x30f9
+ field public static final int EGL_SYNC_FLUSH_COMMANDS_BIT = 1; // 0x1
+ field public static final int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 12528; // 0x30f0
+ field public static final int EGL_SYNC_STATUS = 12529; // 0x30f1
+ field public static final int EGL_SYNC_TYPE = 12535; // 0x30f7
+ field public static final int EGL_TIMEOUT_EXPIRED = 12533; // 0x30f5
+ field public static final int EGL_UNSIGNALED = 12531; // 0x30f3
+ }
+
public class EGLConfig extends android.opengl.EGLObjectHandle {
}
@@ -29741,6 +29800,9 @@
field public static final int EGL_RECORDABLE_ANDROID = 12610; // 0x3142
}
+ public class EGLImage extends android.opengl.EGLObjectHandle {
+ }
+
public abstract class EGLObjectHandle {
ctor protected deprecated EGLObjectHandle(int);
ctor protected EGLObjectHandle(long);
@@ -29751,6 +29813,9 @@
public class EGLSurface extends android.opengl.EGLObjectHandle {
}
+ public class EGLSync extends android.opengl.EGLObjectHandle {
+ }
+
public class ETC1 {
ctor public ETC1();
method public static void decodeBlock(java.nio.Buffer, java.nio.Buffer);
@@ -43041,9 +43106,8 @@
method public static int getDefaultSmsSubscriptionId();
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
- method public static int getSlotIndex(int);
- method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
+ method public static int getSlotIndex(int);
method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
method public boolean isActiveSubscriptionId(int);
@@ -43439,7 +43503,8 @@
package android.telephony.emergency {
- public final class EmergencyNumber implements android.os.Parcelable {
+ public final class EmergencyNumber implements java.lang.Comparable android.os.Parcelable {
+ method public int compareTo(android.telephony.emergency.EmergencyNumber);
method public int describeContents();
method public java.lang.String getCountryIso();
method public int getEmergencyNumberSourceBitmask();
@@ -52310,6 +52375,7 @@
field public static final int ERROR_UNSAFE_RESOURCE = -16; // 0xfffffff0
field public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3; // 0xfffffffd
field public static final int ERROR_UNSUPPORTED_SCHEME = -10; // 0xfffffff6
+ field public static final int SAFE_BROWSING_THREAT_BILLING = 4; // 0x4
field public static final int SAFE_BROWSING_THREAT_MALWARE = 1; // 0x1
field public static final int SAFE_BROWSING_THREAT_PHISHING = 2; // 0x2
field public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0; // 0x0
diff --git a/api/system-current.txt b/api/system-current.txt
index 87a44ce..580a760 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5604,17 +5604,12 @@
}
public final class DataProfile implements android.os.Parcelable {
- ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
- ctor public DataProfile(android.os.Parcel);
- method public int describeContents();
method public java.lang.String getApn();
method public int getAuthType();
method public int getBearerBitmap();
method public int getMaxConns();
method public int getMaxConnsTime();
method public int getMtu();
- method public java.lang.String getMvnoMatchData();
- method public java.lang.String getMvnoType();
method public java.lang.String getPassword();
method public int getProfileId();
method public java.lang.String getProtocol();
@@ -5624,9 +5619,8 @@
method public java.lang.String getUserName();
method public int getWaitTime();
method public boolean isEnabled();
- method public boolean isModemCognitive();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+ method public boolean isPersistent();
+ method public boolean isPreferred();
field public static final int TYPE_3GPP = 1; // 0x1
field public static final int TYPE_3GPP2 = 2; // 0x2
field public static final int TYPE_COMMON = 0; // 0x0
@@ -5952,11 +5946,13 @@
}
public final class ImsExternalCallState implements android.os.Parcelable {
+ ctor public ImsExternalCallState(java.lang.String, android.net.Uri, android.net.Uri, boolean, int, int, boolean);
method public int describeContents();
method public android.net.Uri getAddress();
method public int getCallId();
method public int getCallState();
method public int getCallType();
+ method public android.net.Uri getLocalAddress();
method public boolean isCallHeld();
method public boolean isCallPullable();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index c396cd1..5818f5d 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -46,6 +46,7 @@
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
src/matchers/CombinationLogMatchingTracker.cpp \
+ src/matchers/EventMatcherWizard.cpp \
src/matchers/matcher_util.cpp \
src/matchers/SimpleLogMatchingTracker.cpp \
src/metrics/MetricProducer.cpp \
@@ -217,6 +218,7 @@
tests/metrics/metrics_test_helper.cpp \
tests/statsd_test_util.cpp \
tests/e2e/WakelockDuration_e2e_test.cpp \
+ tests/e2e/MetricActivation_e2e_test.cpp \
tests/e2e/MetricConditionLink_e2e_test.cpp \
tests/e2e/Alarm_e2e_test.cpp \
tests/e2e/Attribution_e2e_test.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 6a9e8a1..3e8b9b8 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -194,7 +194,7 @@
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
- FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+ FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
@@ -219,6 +219,7 @@
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.cpp b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
new file mode 100644
index 0000000..8418e98
--- /dev/null
+++ b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "EventMatcherWizard.h"
+#include <unordered_set>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::string;
+using std::vector;
+
+MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcher_index) {
+ if (matcher_index < 0 || matcher_index >= (int)mAllEventMatchers.size()) {
+ return MatchingState::kNotComputed;
+ }
+ vector<MatchingState> matcherCache(mAllEventMatchers.size(), MatchingState::kNotComputed);
+ mAllEventMatchers[matcher_index]->onLogEvent(event, mAllEventMatchers, matcherCache);
+ return matcherCache[matcher_index];
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.h b/cmds/statsd/src/matchers/EventMatcherWizard.h
new file mode 100644
index 0000000..57ec2b3
--- /dev/null
+++ b/cmds/statsd/src/matchers/EventMatcherWizard.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "LogMatchingTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class EventMatcherWizard : public virtual android::RefBase {
+public:
+ EventMatcherWizard(){}; // for testing
+ EventMatcherWizard(const std::vector<sp<LogMatchingTracker>>& eventTrackers)
+ : mAllEventMatchers(eventTrackers){};
+
+ virtual ~EventMatcherWizard(){};
+
+ MatchingState matchLogEvent(const LogEvent& event, int matcher_index);
+
+private:
+ std::vector<sp<LogMatchingTracker>> mAllEventMatchers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 02b9773..f5a16e9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -69,11 +69,16 @@
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int pullTagId,
+ 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),
+ mWhatMatcherIndex(whatMatcherIndex),
+ mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
mPullTagId(pullTagId),
mTriggerAtomId(triggerAtomId),
@@ -136,7 +141,7 @@
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
if (mIsPulled) {
- pullLocked(startTimeNs);
+ pullAndMatchEventsLocked(startTimeNs);
}
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
@@ -302,7 +307,7 @@
mPastBuckets.clear();
}
-void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
+void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
switch(mSamplingType) {
// When the metric wants to do random sampling and there is already one gauge atom for the
@@ -331,7 +336,10 @@
return;
}
for (const auto& data : allData) {
- onMatchedLogEventLocked(0, *data);
+ if (mEventMatcherWizard->matchLogEvent(
+ *data, mWhatMatcherIndex) == MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ }
}
}
@@ -341,7 +349,7 @@
flushIfNeededLocked(eventTimeNs);
mCondition = conditionMet;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
}
@@ -354,7 +362,7 @@
// pull for every dimension.
mCondition = overallCondition;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
}
@@ -387,7 +395,10 @@
return;
}
for (const auto& data : allData) {
- onMatchedLogEventLocked(0, *data);
+ if (mEventMatcherWizard->matchLogEvent(
+ *data, mWhatMatcherIndex) == MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ }
}
}
@@ -426,7 +437,7 @@
flushIfNeededLocked(eventTimeNs);
if (mTriggerAtomId == event.GetTagId()) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
return;
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 6379389..99827bb 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -24,6 +24,7 @@
#include "../external/PullDataReceiver.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/matcher_util.h"
+#include "../matchers/EventMatcherWizard.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "../stats_util.h"
@@ -56,7 +57,9 @@
class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
- const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
+ 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);
@@ -78,7 +81,7 @@
flushCurrentBucketLocked(eventTimeNs);
mCurrentBucketStartTimeNs = eventTimeNs;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
}
};
@@ -113,7 +116,11 @@
void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
- void pullLocked(const int64_t timestampNs);
+ void pullAndMatchEventsLocked(const int64_t timestampNs);
+
+ const int mWhatMatcherIndex;
+
+ sp<EventMatcherWizard> mEventMatcherWizard;
sp<StatsPullerManager> mPullerManager;
// tagId for pulled data. -1 if this is not pulled
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index df08181..f87849e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -64,8 +64,54 @@
onMatchedLogEventInternalLocked(
matcherIndex, metricKey, conditionKey, condition, event);
}
+}
- }
+bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
+ bool isActive = mEventActivationMap.empty();
+ for (auto& it : mEventActivationMap) {
+ if (it.second.state == ActivationState::kActive &&
+ elapsedTimestampNs > it.second.ttl_ns + it.second.activation_ns) {
+ it.second.state = ActivationState::kNotActive;
+ }
+ if (it.second.state == ActivationState::kActive) {
+ isActive = true;
+ }
+ }
+ return isActive;
+}
+
+void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mIsActive) {
+ return;
+ }
+ mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
+ if (!mIsActive) {
+ flushLocked(elapsedTimestampNs);
+ }
+}
+
+void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ // When a metric producer does not depend on any activation, its mIsActive is true.
+ // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
+ // change.
+ if (mEventActivationMap.empty()) {
+ mIsActive = false;
+ }
+ mEventActivationMap[activationTrackerIndex].ttl_ns = ttl_seconds * NS_PER_SEC;
+}
+
+void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
+ auto it = mEventActivationMap.find(activationTrackerIndex);
+ if (it == mEventActivationMap.end()) {
+ return;
+ }
+ it->second.activation_ns = elapsedTimestampNs;
+ it->second.state = ActivationState::kActive;
+ mIsActive = true;
+}
+
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 6fe4bfb..b21fd50 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -34,6 +34,17 @@
namespace os {
namespace statsd {
+// If the metric has no activation requirement, it will be active once the metric producer is
+// created.
+// If the metric needs to be activated by atoms, the metric producer will start
+// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
+// when it reaches the duration limit (timebomb). If the activation event arrives again before
+// or after it expires, the event producer will be re-activated and ttl will be reset.
+enum ActivationState {
+ kNotActive = 0,
+ kActive = 1,
+};
+
// 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
@@ -54,7 +65,8 @@
mContainANYPositionInDimensionsInWhat(false),
mSliceByPositionALL(false),
mSameConditionDimensionsInTracker(false),
- mHasLinksToAllConditionDimensionsInTracker(false) {
+ mHasLinksToAllConditionDimensionsInTracker(false),
+ mIsActive(true) {
}
virtual ~MetricProducer(){};
@@ -93,17 +105,23 @@
// Consume the parsed stats log entry that already matched the "what" of the metric.
void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
- onMatchedLogEventLocked(matcherIndex, event);
+ if (mIsActive) {
+ onMatchedLogEventLocked(matcherIndex, event);
+ }
}
void onConditionChanged(const bool condition, const int64_t eventTime) {
std::lock_guard<std::mutex> lock(mMutex);
- onConditionChangedLocked(condition, eventTime);
+ if (mIsActive) {
+ onConditionChangedLocked(condition, eventTime);
+ }
}
void onSlicedConditionMayChange(bool overallCondition, const int64_t eventTime) {
std::lock_guard<std::mutex> lock(mMutex);
- onSlicedConditionMayChangeLocked(overallCondition, eventTime);
+ if (mIsActive) {
+ onSlicedConditionMayChangeLocked(overallCondition, eventTime);
+ }
}
bool isConditionSliced() const {
@@ -177,6 +195,15 @@
return mCurrentBucketNum;
}
+ void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ activateLocked(activationTrackerIndex, elapsedTimestampNs);
+ }
+
+ void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
+
+ void flushIfExpire(int64_t elapsedTimestampNs);
+
protected:
virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -189,6 +216,10 @@
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
+ bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
+
+ void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
+
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
@@ -198,9 +229,9 @@
/**
* Flushes all the data including the current partial bucket.
*/
- virtual void flushLocked(const int64_t& eventTime) {
- flushIfNeededLocked(eventTime);
- flushCurrentBucketLocked(eventTime);
+ virtual void flushLocked(const int64_t& eventTimeNs) {
+ flushIfNeededLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs);
};
/**
@@ -295,6 +326,21 @@
virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
mutable std::mutex mMutex;
+
+ struct Activation {
+ Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive) {}
+
+ int64_t ttl_ns;
+ int64_t activation_ns;
+ ActivationState state;
+ };
+ // 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, Activation> mEventActivationMap;
+
+ bool mIsActive;
+
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 0e5ef4d..f85ba1f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -73,7 +73,8 @@
key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
- mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
+ mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
+ mActivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
@@ -298,7 +299,12 @@
}
int tagId = event.GetTagId();
- int64_t eventTime = event.GetElapsedTimestampNs();
+ int64_t eventTimeNs = event.GetElapsedTimestampNs();
+
+ for (int metric : mMetricIndexesWithActivation) {
+ mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
+ }
+
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
@@ -310,6 +316,14 @@
matcher->onLogEvent(event, mAllAtomMatchers, matcherCache);
}
+ for (const auto& it : mActivationAtomTrackerToMetricMap) {
+ if (matcherCache[it.first] == MatchingState::kMatched) {
+ for (int metricIndex : it.second) {
+ mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
+ }
+ }
+ }
+
// A bitmap to see which ConditionTracker needs to be re-evaluated.
vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
@@ -347,13 +361,13 @@
// Push the new condition to it directly.
if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
- eventTime);
+ eventTimeNs);
// metric cares about sliced conditions, and it may have changed. Send
// notification, and the metric can query the sliced conditions that are
// interesting to it.
} else {
mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
- eventTime);
+ eventTimeNs);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index dfbb69f..649222ff 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -195,6 +195,11 @@
// maps from ConditionTracker to MetricProducer
std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
+ // maps from life span triggering event to MetricProducers.
+ std::unordered_map<int, std::vector<int>> mActivationAtomTrackerToMetricMap;
+
+ std::vector<int> mMetricIndexesWithActivation;
+
void initLogSourceWhiteList();
// The metrics that don't need to be uploaded or even reported.
@@ -207,7 +212,7 @@
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
- FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+ FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
@@ -230,6 +235,7 @@
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 75d6df9..136ba07 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -25,6 +25,7 @@
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
+#include "../matchers/EventMatcherWizard.h"
#include "../metrics/CountMetricProducer.h"
#include "../metrics/DurationMetricProducer.h"
#include "../metrics/EventMetricProducer.h"
@@ -294,6 +295,7 @@
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
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();
allMetricProducers.reserve(allMetricsCount);
@@ -563,7 +565,8 @@
}
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
- key, metric, conditionIndex, wizard, pullTagId, triggerAtomId, atomTagId,
+ key, metric, conditionIndex, wizard,
+ trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
timeBaseTimeNs, currentTimeNs, pullerManager);
allMetricProducers.push_back(gaugeProducer);
}
@@ -682,6 +685,44 @@
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,
+ 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;
+ }
+ 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);
+ allMetricProducers[metricTrackerIndex]->addActivation(
+ atomMatcherIndex, activation.ttl_seconds());
+ }
+ }
+ return true;
+}
+
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -695,6 +736,8 @@
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
unordered_map<int64_t, int> conditionTrackerMap;
@@ -729,6 +772,11 @@
ALOGE("initAlarms failed");
return false;
}
+ if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
+ allMetricProducers, activationAtomTrackerToMetricMap, metricsWithActivation)) {
+ ALOGE("initMetricActivations failed");
+ return false;
+ }
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index c660149..9ffceda 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -108,6 +108,8 @@
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ unordered_map<int, std::vector<int>>& lifeSpanEventTrackerToMetricMap,
+ vector<int>& metricsWithLifeSpan,
std::set<int64_t>& noReportMetricIds);
bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index d19e247..d5f81a59 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -347,6 +347,17 @@
optional float probability_of_informing = 7 [default = 1.1];
}
+message EventActivation {
+ optional int64 atom_matcher_id = 1;
+ optional int64 ttl_seconds = 2;
+}
+
+message MetricActivation {
+ optional int64 metric_id = 1;
+
+ repeated EventActivation event_activation = 2;
+}
+
message StatsdConfig {
optional int64 id = 1;
@@ -384,6 +395,8 @@
optional bool hash_strings_in_metric_report = 16 [default = true];
+ repeated MetricActivation metric_activation = 17;
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 8fbb58a..f8184d8 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -282,13 +282,17 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
EXPECT_EQ(1u, allAnomalyTrackers.size());
EXPECT_EQ(1u, noReportMetricIds.size());
@@ -309,13 +313,17 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -333,13 +341,17 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -357,12 +369,16 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -380,12 +396,16 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -403,13 +423,17 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -427,13 +451,17 @@
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
#else
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 5729feb..d7b9c11 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -200,8 +200,8 @@
EXPECT_GT(data.bucket_info(5).atom(0).temperature().temperature_deci_celsius(), 0);
}
-TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
- auto config = CreateStatsdConfig(GaugeMetric::ALL_CONDITION_CHANGES);
+TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
int64_t baseTimeNs = 10 * NS_PER_SEC;
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
new file mode 100644
index 0000000..0f13a4a
--- /dev/null
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -0,0 +1,242 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig() {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto crashMatcher = CreateProcessCrashAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
+
+ *config.add_atom_matcher() = saverModeMatcher;
+ *config.add_atom_matcher() = crashMatcher;
+ *config.add_atom_matcher() = screenOnMatcher;
+
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(crashMatcher.id());
+ countMetric->set_bucket(FIVE_MINUTES);
+ countMetric->mutable_dimensions_in_what()->set_field(
+ android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ countMetric->mutable_dimensions_in_what()->add_child()->set_field(1); // uid field
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(metricId);
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(saverModeMatcher.id());
+ event_activation1->set_ttl_seconds(60 * 6); // 6 minutes
+ auto event_activation2 = metric_activation1->add_event_activation();
+ event_activation2->set_atom_matcher_id(screenOnMatcher.id());
+ event_activation2->set_ttl_seconds(60 * 2); // 2 minutes
+
+ return config;
+}
+
+} // namespace
+
+TEST(MetricActivationE2eTest, TestCountMetric) {
+ auto config = CreateStatsdConfig();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ sp<MetricProducer> metricProducer =
+ processor->mMetricsManagers.begin()->second->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricProducer->mIsActive);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // First processed event.
+ event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
+ processor->OnLogEvent(event.get());
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 20);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+ processor->OnLogEvent(event.get());
+
+ // All activations expired.
+ event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // Re-activate.
+ event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP,
+ &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(4, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+}
+
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index bf58b9c..60bd4a7 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/matchers/SimpleLogMatchingTracker.h"
#include "src/metrics/GaugeMetricProducer.h"
#include "src/stats_log_util.h"
#include "logd/LogEvent.h"
@@ -40,6 +41,8 @@
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
+const int64_t atomMatcherId = 678;
+const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -61,11 +64,19 @@
gaugeFieldMatcher->add_child()->set_field(3);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
// statsd started long ago.
// The metric starts in the middle of the bucket
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
@@ -86,6 +97,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -103,6 +120,7 @@
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -178,7 +196,15 @@
alert.set_num_buckets(100);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
@@ -246,6 +272,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -263,6 +295,7 @@
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -315,6 +348,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -330,7 +369,8 @@
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, -1, tagId,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
@@ -388,6 +428,12 @@
dim->set_field(conditionTag);
dim->add_child()->set_field(1);
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
.WillRepeatedly(
@@ -420,7 +466,8 @@
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, -1, tagId,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -463,7 +510,15 @@
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -542,6 +597,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
@@ -574,6 +635,7 @@
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -632,6 +694,12 @@
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
@@ -667,6 +735,7 @@
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 56ca98f..1a8a32e 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2354,6 +2354,7 @@
android.nfc.NfcAdapter$CreateNdefMessageCallback
android.nfc.NfcManager
android.opengl.EGL14
+android.opengl.EGL15
android.opengl.EGLConfig
android.opengl.EGLContext
android.opengl.EGLDisplay
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index aca80b4..3cc5e37 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4678,7 +4678,7 @@
if (decor != null) {
decor.cancelPendingInputEvents();
}
- if (options != null && !isTopOfTask()) {
+ if (options != null) {
mActivityTransitionState.startExitOutTransition(this, options);
}
}
@@ -4882,6 +4882,7 @@
Bundle options)
throws IntentSender.SendIntentException {
try {
+ options = transferSpringboardActivityOptions(options);
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
@@ -4898,6 +4899,12 @@
throw new IntentSender.SendIntentException();
}
Instrumentation.checkStartActivityResult(result, null);
+
+ if (options != null) {
+ // Only when the options are not null, as the intent can point to something other
+ // than an Activity.
+ cancelInputsAndStartExitTransition(options);
+ }
} catch (RemoteException e) {
}
if (requestCode >= 0) {
@@ -6471,7 +6478,7 @@
*
* @return true if this is the topmost, non-finishing activity in its task.
*/
- private boolean isTopOfTask() {
+ final boolean isTopOfTask() {
if (mToken == null || mWindow == null) {
return false;
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 7ae2ded..d00650d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -244,4 +244,10 @@
public abstract void updateOomLevelsForDisplay(int displayId);
public abstract boolean isActivityStartsLoggingEnabled();
public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);
+
+ /** Input dispatch timeout to a window, start the ANR process. */
+ public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
+ public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
+ boolean aboveSystem, String reason);
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 3c9a2d4..94b42ff 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -195,6 +195,13 @@
private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
/**
+ * See {@link #setPendingIntentLaunchFlags(int)}
+ * @hide
+ */
+ private static final String KEY_PENDING_INTENT_LAUNCH_FLAGS =
+ "android.activity.pendingIntentLaunchFlags";
+
+ /**
* See {@link #setTaskOverlay}.
* @hide
*/
@@ -309,6 +316,7 @@
@WindowConfiguration.ActivityType
private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
+ private int mPendingIntentLaunchFlags;
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
@@ -932,6 +940,7 @@
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
+ mPendingIntentLaunchFlags = opts.getInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, 0);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@@ -1233,6 +1242,22 @@
}
/**
+ * Specifies intent flags to be applied for any activity started from a PendingIntent.
+ *
+ * @hide
+ */
+ public void setPendingIntentLaunchFlags(@android.content.Intent.Flags int flags) {
+ mPendingIntentLaunchFlags = flags;
+ }
+
+ /**
+ * @hide
+ */
+ public int getPendingIntentLaunchFlags() {
+ return mPendingIntentLaunchFlags;
+ }
+
+ /**
* Set's whether the activity launched with this option should be a task overlay. That is the
* activity will always be the top activity of the task. If {@param canResume} is true, then
* the task will also not be moved to the front of the stack.
@@ -1463,6 +1488,9 @@
if (mLaunchTaskId != -1) {
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
}
+ if (mPendingIntentLaunchFlags != 0) {
+ b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
+ }
if (mTaskOverlay) {
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9b2bfc5..4b87a64 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -193,6 +193,13 @@
*/
public static final int MSG_SHARED_ELEMENT_DESTINATION = 107;
+ /**
+ * Sent by Activity#startActivity to notify the entering activity that enter animation for
+ * back is allowed. If this message is not received, the default exit animation will run when
+ * backing out of an activity (instead of the 'reverse' shared element transition).
+ */
+ public static final int MSG_ALLOW_RETURN_TRANSITION = 108;
+
private Window mWindow;
final protected ArrayList<String> mAllSharedElementNames;
final protected ArrayList<View> mSharedElements = new ArrayList<View>();
@@ -346,8 +353,6 @@
return new ArrayList<View>(mSharedElements);
}
- public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
-
protected Transition setTargets(Transition transition, boolean add) {
if (transition == null || (add &&
(mTransitioningViews == null || mTransitioningViews.isEmpty()))) {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index b8f5a8e..3201feb 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -35,7 +35,7 @@
*/
class ActivityTransitionState {
- private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements";
+ private static final String PENDING_EXIT_SHARED_ELEMENTS = "android:pendingExitSharedElements";
private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom";
@@ -43,9 +43,9 @@
/**
* The shared elements that the calling Activity has said that they transferred to this
- * Activity.
+ * Activity and will be transferred back during exit animation.
*/
- private ArrayList<String> mEnteringNames;
+ private ArrayList<String> mPendingExitNames;
/**
* The names of shared elements that were shared to the called Activity.
@@ -112,8 +112,7 @@
public int addExitTransitionCoordinator(ExitTransitionCoordinator exitTransitionCoordinator) {
if (mExitTransitionCoordinators == null) {
- mExitTransitionCoordinators =
- new SparseArray<WeakReference<ExitTransitionCoordinator>>();
+ mExitTransitionCoordinators = new SparseArray<>();
}
WeakReference<ExitTransitionCoordinator> ref = new WeakReference(exitTransitionCoordinator);
// clean up old references:
@@ -132,7 +131,7 @@
public void readState(Bundle bundle) {
if (bundle != null) {
if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) {
- mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS);
+ mPendingExitNames = bundle.getStringArrayList(PENDING_EXIT_SHARED_ELEMENTS);
}
if (mEnterTransitionCoordinator == null) {
mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM);
@@ -141,9 +140,21 @@
}
}
+ /**
+ * Returns the element names to be used for exit animation. It caches the list internally so
+ * that it is preserved through activty destroy and restore.
+ */
+ private ArrayList<String> getPendingExitNames() {
+ if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+ mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
+ }
+ return mPendingExitNames;
+ }
+
public void saveState(Bundle bundle) {
- if (mEnteringNames != null) {
- bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames);
+ ArrayList<String> pendingExitNames = getPendingExitNames();
+ if (pendingExitNames != null) {
+ bundle.putStringArrayList(PENDING_EXIT_SHARED_ELEMENTS, pendingExitNames);
}
if (mExitingFrom != null) {
bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom);
@@ -226,7 +237,7 @@
}
} else {
mEnterTransitionCoordinator.namedViewsReady(null, null);
- mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames();
+ mPendingExitNames = null;
}
mExitingFrom = null;
@@ -268,7 +279,7 @@
}
public void clear() {
- mEnteringNames = null;
+ mPendingExitNames = null;
mExitingFrom = null;
mExitingTo = null;
mExitingToView = null;
@@ -296,7 +307,8 @@
}
public boolean startExitBackTransition(final Activity activity) {
- if (mEnteringNames == null || mCalledExitCoordinator != null) {
+ ArrayList<String> pendingExitNames = getPendingExitNames();
+ if (pendingExitNames == null || mCalledExitCoordinator != null) {
return false;
} else {
if (!mHasExited) {
@@ -315,7 +327,7 @@
}
mReturnExitCoordinator = new ExitTransitionCoordinator(activity,
- activity.getWindow(), activity.mEnterTransitionListener, mEnteringNames,
+ activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames,
null, null, true);
if (enterViewsTransition != null && decor != null) {
enterViewsTransition.resume(decor);
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index ab847fd..bce243c 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -65,6 +65,7 @@
private OneShotPreDrawListener mViewsReadyListener;
private final boolean mIsCrossTask;
private Drawable mReplacedBackground;
+ private ArrayList<String> mPendingExitNames;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
@@ -249,6 +250,11 @@
case MSG_CANCEL:
cancel();
break;
+ case MSG_ALLOW_RETURN_TRANSITION:
+ if (!mIsCanceled) {
+ mPendingExitNames = mAllSharedElementNames;
+ }
+ break;
}
}
@@ -256,6 +262,10 @@
return mIsReturning && mResultReceiver != null;
}
+ public ArrayList<String> getPendingExitSharedElementNames() {
+ return mPendingExitNames;
+ }
+
/**
* This is called onResume. If an Activity is resuming and the transitions
* haven't started yet, force the views to appear. This is likely to be
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index df31da9..48a711e 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -433,6 +433,11 @@
if (!mSharedElementNotified) {
mSharedElementNotified = true;
delayCancel();
+
+ if (!mActivity.isTopOfTask()) {
+ mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null);
+ }
+
if (mListener == null) {
mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
notifyExitComplete();
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index a9cb0d9..f71fdd7 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1198,6 +1198,19 @@
/** {@hide} */
public static int translateModeStringToPosix(String mode) {
+ // Sanity check for invalid chars
+ for (int i = 0; i < mode.length(); i++) {
+ switch (mode.charAt(i)) {
+ case 'r':
+ case 'w':
+ case 't':
+ case 'a':
+ break;
+ default:
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ }
+
int res = 0;
if (mode.startsWith("rw")) {
res |= O_RDWR | O_CREAT;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 384115b..0c56d48 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.opengl.EGL14;
import android.os.Build;
@@ -30,6 +31,7 @@
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -54,6 +56,7 @@
private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0";
private static final String ANGLE_PACKAGE_NAME = "com.android.angle";
private static final String GLES_MODE_METADATA_KEY = "com.android.angle.GLES_MODE";
+ private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private ClassLoader mClassLoader;
private String mLayerPath;
@@ -250,8 +253,40 @@
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
+ // Pass the rules file to loader for ANGLE decisions
+ AssetManager angleAssets = null;
+ try {
+ angleAssets =
+ context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to get AssetManager for '" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ AssetFileDescriptor assetsFd = null;
+ try {
+ assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + " from "
+ + "'" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ FileDescriptor rulesFd = null;
+ long rulesOffset = 0;
+ long rulesLength = 0;
+ if (assetsFd != null) {
+ rulesFd = assetsFd.getFileDescriptor();
+ rulesOffset = assetsFd.getStartOffset();
+ rulesLength = assetsFd.getLength();
+ } else {
+ Log.w(TAG, "Failed to get file descriptor for " + ANGLE_RULES_FILE);
+ return;
+ }
+
// Further opt-in logic is handled in native, so pass relevant info down
- setAngleInfo(paths, packageName, appPref, devOptIn);
+ setAngleInfo(paths, packageName, appPref, devOptIn,
+ rulesFd, rulesOffset, rulesLength);
}
/**
@@ -391,5 +426,6 @@
private static native void setDebugLayers(String layers);
private static native void setDriverPath(String path);
private static native void setAngleInfo(String path, String appPackage, String appPref,
- boolean devOptIn);
+ boolean devOptIn, FileDescriptor rulesFd,
+ long rulesOffset, long rulesLength);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 22bce1d..ad64021 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12381,6 +12381,28 @@
"sms_access_restriction_enabled";
/**
+ * If set to 1, an app must have the READ_PRIVILEGED_PHONE_STATE permission (or be a device
+ * / profile owner with the READ_PHONE_STATE permission) to access device identifiers.
+ *
+ * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+ *
+ * @hide
+ */
+ public static final String PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED =
+ "privileged_device_identifier_check_enabled";
+
+ /**
+ * If set to 1, an app that is targeting Q and does not meet the new requirements to access
+ * device identifiers will receive a SecurityException.
+ *
+ * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+ *
+ * @hide
+ */
+ public static final String PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED =
+ "privileged_device_identifier_target_q_behavior_enabled";
+
+ /**
* If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
* and restoring to lower version of platform API will be skipped.
*
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e8e4b4ab..a401c6d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1052,13 +1052,6 @@
mNextServedView = null;
if (mServedView != null) {
if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));
- if (mCurrentTextBoxAttribute != null) {
- try {
- mService.finishInput(mClient);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
mServedView = null;
mCompletions = null;
mServedConnecting = false;
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index bdd7a09..69d7202 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -282,19 +282,28 @@
SAFE_BROWSING_THREAT_UNKNOWN,
SAFE_BROWSING_THREAT_MALWARE,
SAFE_BROWSING_THREAT_PHISHING,
- SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE,
+ SAFE_BROWSING_THREAT_BILLING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SafeBrowsingThreat {}
- /** The resource was blocked for an unknown reason */
+ /** The resource was blocked for an unknown reason. */
public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0;
- /** The resource was blocked because it contains malware */
+ /** The resource was blocked because it contains malware. */
public static final int SAFE_BROWSING_THREAT_MALWARE = 1;
- /** The resource was blocked because it contains deceptive content */
+ /** The resource was blocked because it contains deceptive content. */
public static final int SAFE_BROWSING_THREAT_PHISHING = 2;
- /** The resource was blocked because it contains unwanted software */
+ /** The resource was blocked because it contains unwanted software. */
public static final int SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE = 3;
+ /**
+ * The resource was blocked because it may trick the user into a billing agreement.
+ *
+ * <p>This constant is only used when targetSdkVersion is greater than {@link
+ * android.os.Build.VERSION_CODES#Q}. Otherwise, {@link #SAFE_BROWSING_THREAT_UNKNOWN} is used
+ * instead.
+ */
+ public static final int SAFE_BROWSING_THREAT_BILLING = 4;
/**
* Report an error to the host application. These errors are unrecoverable
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8f17e96..4d03123 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -370,10 +370,12 @@
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
ActivityOptions opts = getActivityOptions(context);
+ // The NEW_TASK flags are applied through the activity options and not as a part of
+ // the call to startIntentSender() to ensure that they are consistently applied to
+ // both mutable and immutable PendingIntents.
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
+ 0, 0, 0, opts.toBundle());
} catch (IntentSender.SendIntentException e) {
android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
return false;
@@ -401,10 +403,15 @@
windowAnimationStyle.recycle();
if (enterAnimationId != 0) {
- return ActivityOptions.makeCustomAnimation(context, enterAnimationId, 0);
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(context,
+ enterAnimationId, 0);
+ opts.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return opts;
}
}
- return ActivityOptions.makeBasic();
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return opts;
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index dceacda..34e8501 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -46,7 +46,6 @@
// Currently there is a bug that aidl doesn't accept List<Parcelable>
List getShortcutInputMethodsAndSubtypes();
- void finishInput(in IInputMethodClient client);
boolean showSoftInput(in IInputMethodClient client, int flags,
in ResultReceiver resultReceiver);
boolean hideSoftInput(in IInputMethodClient client, int flags,
diff --git a/core/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java
index c029bb2..3ea873b 100644
--- a/core/java/com/google/android/collect/Lists.java
+++ b/core/java/com/google/android/collect/Lists.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +34,7 @@
*
* @return a newly-created, initially-empty {@code ArrayList}
*/
+ @UnsupportedAppUsage
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index fc2c9fe..6ba3320 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import java.util.HashMap;
@@ -29,6 +30,7 @@
*
* @return a newly-created, initially-empty {@code HashMap}
*/
+ @UnsupportedAppUsage
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ed6445d..59c29e2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -45,6 +45,7 @@
"android_app_NativeActivity.cpp",
"android_app_admin_SecurityLog.cpp",
"android_opengl_EGL14.cpp",
+ "android_opengl_EGL15.cpp",
"android_opengl_EGLExt.cpp",
"android_opengl_GLES10.cpp",
"android_opengl_GLES10Ext.cpp",
@@ -239,6 +240,7 @@
shared_libs: [
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"libmemtrack",
"libandroidfw",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c05bad2..eada690 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -77,6 +77,7 @@
extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
extern int register_android_opengl_jni_EGL14(JNIEnv* env);
+extern int register_android_opengl_jni_EGL15(JNIEnv* env);
extern int register_android_opengl_jni_EGLExt(JNIEnv* env);
extern int register_android_opengl_jni_GLES10(JNIEnv* env);
extern int register_android_opengl_jni_GLES10Ext(JNIEnv* env);
@@ -1367,6 +1368,7 @@
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_EGL14),
+ REG_JNI(register_android_opengl_jni_EGL15),
REG_JNI(register_android_opengl_jni_EGLExt),
REG_JNI(register_android_opengl_jni_GLES10),
REG_JNI(register_android_opengl_jni_GLES10Ext),
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 2619107..bb291e7 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -23,8 +23,6 @@
#include <hwui/Paint.h>
#include <utils/Log.h>
-#include <ResourceCache.h>
-
#include "SkCanvas.h"
#include "SkLatticeIter.h"
#include "SkRegion.h"
@@ -83,12 +81,7 @@
static void finalize(JNIEnv* env, jobject, jlong patchHandle) {
int8_t* patch = reinterpret_cast<int8_t*>(patchHandle);
- if (android::uirenderer::ResourceCache::hasInstance()) {
- Res_png_9patch* p = (Res_png_9patch*) patch;
- android::uirenderer::ResourceCache::getInstance().destructor(p);
- } else {
- delete[] patch;
- }
+ delete[] patch;
}
static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap,
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
new file mode 100644
index 0000000..4a30bab
--- /dev/null
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -0,0 +1,557 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <assert.h>
+#include <EGL/egl.h>
+
+#include <ui/ANativeObjectBase.h>
+
+static int initialized = 0;
+
+// classes from EGL 1.4
+static jclass egldisplayClass;
+static jclass eglsurfaceClass;
+static jclass eglconfigClass;
+static jclass eglcontextClass;
+static jclass bufferClass;
+static jclass nioAccessClass;
+
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+
+static jmethodID egldisplayGetHandleID;
+static jmethodID eglconfigGetHandleID;
+static jmethodID eglcontextGetHandleID;
+static jmethodID eglsurfaceGetHandleID;
+
+static jmethodID egldisplayConstructor;
+static jmethodID eglcontextConstructor;
+static jmethodID eglsurfaceConstructor;
+static jmethodID eglconfigConstructor;
+
+static jobject eglNoContextObject;
+static jobject eglNoDisplayObject;
+static jobject eglNoSurfaceObject;
+
+// classes from EGL 1.5
+static jclass eglimageClass;
+static jclass eglsyncClass;
+
+static jmethodID eglimageGetHandleID;
+static jmethodID eglsyncGetHandleID;
+
+static jmethodID eglimageConstructor;
+static jmethodID eglsyncConstructor;
+
+static jobject eglNoImageObject;
+static jobject eglNoSyncObject;
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+ // EGL 1.4 Init
+ jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
+ eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
+ jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
+ eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
+ jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
+ egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
+ jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
+ eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
+
+ eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
+ eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+ egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+ eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+
+
+ eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
+ eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+ egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+ eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+ eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+ eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
+ eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+
+
+ jclass eglClass = _env->FindClass("android/opengl/EGL15");
+ jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+ _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
+
+ jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+ _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
+
+ jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+ _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
+
+ // EGL 1.5 init
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+
+ jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
+ eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal);
+ jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+ eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
+
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
+ eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
+
+ jfieldID noImageFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+ _env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
+
+ jfieldID noSyncFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+ _env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return reinterpret_cast<void*>(pointer);
+ }
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+ getBaseArrayID, buffer);
+ *offset = _env->CallStaticIntMethod(nioAccessClass,
+ getBaseArrayOffsetID, buffer);
+
+ return NULL;
+}
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
+}
+
+static void *
+fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+ if (obj == NULL){
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Object is set to null.");
+ }
+
+ jlong handle = _env->CallLongMethod(obj, mid);
+ return reinterpret_cast<void*>(handle);
+}
+
+static jobject
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
+ if (cls == eglimageClass &&
+ (EGLImage)handle == EGL_NO_IMAGE) {
+ return eglNoImageObject;
+ }
+
+ return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
+}
+
+// --------------------------------------------------------------------------
+/* EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreateSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jint type, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLSync _returnValue = (EGLSync) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ _returnValue = eglCreateSync(
+ (EGLDisplay)dpy_native,
+ (EGLenum)type,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue);
+}
+
+/* EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync ) */
+static jboolean
+android_eglDestroySync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync) {
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglDestroySync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native
+ );
+ return (jboolean)_returnValue;
+}
+
+/* EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout ) */
+static jint
+android_eglClientWaitSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags, jlong timeout) {
+ EGLint _returnValue = (EGLint) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglClientWaitSync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)flags,
+ (EGLTime)timeout
+ );
+ return (jint)_returnValue;
+}
+
+/* EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value ) */
+static jboolean
+android_eglGetSyncAttrib
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint attribute, jlongArray value_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+ EGLAttrib *value_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *value = (EGLAttrib *) 0;
+
+ if (!value_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "value == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(value_ref) - offset;
+ value_base = (EGLAttrib *)
+ _env->GetLongArrayElements(value_ref, (jboolean *)0);
+ value = value_base + offset;
+
+ _returnValue = eglGetSyncAttrib(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)attribute,
+ (EGLAttrib *)value
+ );
+
+exit:
+ if (value_base) {
+ _env->ReleaseLongArrayElements(value_ref, (jlong*)value_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return (jboolean)_returnValue;
+}
+
+/* EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglGetPlatformDisplay
+ (JNIEnv *_env, jobject _this, jint platform, jlong native_display, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLDisplay _returnValue = (EGLDisplay) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ _returnValue = eglGetPlatformDisplay(
+ (EGLenum)platform,
+ (void *)native_display,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
+}
+
+/* EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreatePlatformWindowSurface
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_window_buf, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ EGLSurface _returnValue = (EGLSurface) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+ jint _native_windowRemaining;
+ void *native_window = (void *) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _attrib_listRemaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!native_window_buf) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "native_window == null";
+ goto exit;
+ }
+ native_window = (void *)getPointer(_env, native_window_buf, (jarray*)&_array, &_native_windowRemaining, &_bufferOffset);
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ if (native_window == NULL) {
+ char * _native_windowBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ native_window = (void *) (_native_windowBase + _bufferOffset);
+ }
+ _returnValue = eglCreatePlatformWindowSurface(
+ (EGLDisplay)dpy_native,
+ (EGLConfig)config_native,
+ (void *)native_window,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_array) {
+ releasePointer(_env, _array, native_window, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
+/* EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreatePlatformPixmapSurface
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ EGLSurface _returnValue = (EGLSurface) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+ jint _native_pixmapRemaining;
+ void *native_pixmap = (void *) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _attrib_listRemaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!native_pixmap_buf) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "native_pixmap == null";
+ goto exit;
+ }
+ native_pixmap = (void *)getPointer(_env, native_pixmap_buf, (jarray*)&_array, &_native_pixmapRemaining, &_bufferOffset);
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ if (native_pixmap == NULL) {
+ char * _native_pixmapBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ native_pixmap = (void *) (_native_pixmapBase + _bufferOffset);
+ }
+ _returnValue = eglCreatePlatformPixmapSurface(
+ (EGLDisplay)dpy_native,
+ (EGLConfig)config_native,
+ (void *)native_pixmap,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_array) {
+ releasePointer(_env, _array, native_pixmap, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
+/* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */
+static jboolean
+android_eglWaitSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags) {
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglWaitSync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)flags
+ );
+ return (jboolean)_returnValue;
+}
+
+static const char *classPathName = "android/opengl/EGL15";
+
+static const JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"eglCreateSync", "(Landroid/opengl/EGLDisplay;I[JI)Landroid/opengl/EGLSync;", (void *) android_eglCreateSync },
+{"eglDestroySync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;)Z", (void *) android_eglDestroySync },
+{"eglClientWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;IJ)I", (void *) android_eglClientWaitSync },
+{"eglGetSyncAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I[JI)Z", (void *) android_eglGetSyncAttrib },
+{"eglGetPlatformDisplay", "(IJ[JI)Landroid/opengl/EGLDisplay;", (void *) android_eglGetPlatformDisplay },
+{"eglCreatePlatformWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformWindowSurface },
+{"eglCreatePlatformPixmapSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformPixmapSurface },
+{"eglWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I)Z", (void *) android_eglWaitSync },
+};
+
+int register_android_opengl_jni_EGL15(JNIEnv *_env)
+{
+ int err;
+ err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+ return err;
+}
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 92235ad..e64da5c 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -32,12 +32,16 @@
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn) {
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn,
+ jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars appPrefChars(env, appPref);
+
+ int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
+
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- appPrefChars.c_str(), devOptIn);
+ appPrefChars.c_str(), devOptIn, rulesFd_native, rulesOffset, rulesLength);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -57,7 +61,7 @@
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
- { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
};
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 109e65c..b3ff4db 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -32,8 +32,8 @@
#include <utils/misc.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::hasBpfSupport;
using android::bpf::parseBpfNetworkStatsDetail;
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 80281b6..6966448 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -41,6 +41,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.Context;
import android.os.FileUtils.MemoryPipe;
@@ -510,6 +511,20 @@
MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
}
+ @Test
+ public void testTranslateMode_Invalid() throws Exception {
+ try {
+ translateModeStringToPosix("rwx");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ translateModeStringToPosix("");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
private static void assertTranslate(String string, int posix, int pfd) {
assertEquals(posix, translateModeStringToPosix(string));
assertEquals(string, translateModePosixToString(posix));
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 632c37f..9778acb 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -368,6 +368,8 @@
Settings.Global.PRIV_APP_OOB_ENABLED,
Settings.Global.PRIV_APP_OOB_LIST,
Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index c98e646..7360e9f 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -20,7 +20,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.util.KeyUtils;
import android.view.KeyEvent;
@@ -239,7 +238,6 @@
}
@Test
- @Suppress
public void testEmojiModifier() {
EditorState state = new EditorState();
@@ -256,20 +254,15 @@
// Isolated multiple emoji modifier
state.setByString("| U+1F3FB U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
// Multiple emoji modifiers
state.setByString("| U+1F466 U+1F3FB U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
}
@Test
- @Suppress
public void testMixedEdgeCases() {
EditorState state = new EditorState();
@@ -318,7 +311,7 @@
// COMBINING ENCLOSING KEYCAP + emoji modifier
state.setByString("| '1' U+20E3 U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// Emoji modifier + COMBINING ENCLOSING KEYCAP
state.setByString("| U+1F466 U+1F3FB U+20E3");
@@ -360,7 +353,7 @@
// Variation selector + emoji modifier
state.setByString("| U+2665 U+FE0F U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// Emoji modifier + variation selector
state.setByString("| U+1F466 U+1F3FB U+FE0F");
@@ -396,7 +389,7 @@
// Start with ZERO WIDTH JOINER + emoji modifier
state.setByString("| U+200D U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// ZERO WIDTH JOINER + emoji modifier
state.setByString("| U+1F469 U+200D U+1F3FB");
@@ -418,8 +411,6 @@
// Regional indicator symbol + emoji modifier
state.setByString("| U+1F1FA U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
// Emoji modifier + regional indicator symbol
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index e3ec45b..503951d 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -202,9 +202,7 @@
"AnimationContext.cpp",
"Animator.cpp",
"AnimatorManager.cpp",
- "CanvasState.cpp",
"CanvasTransform.cpp",
- "ClipArea.cpp",
"DamageAccumulator.cpp",
"DeferredLayerUpdater.cpp",
"DeviceInfo.cpp",
@@ -227,9 +225,7 @@
"RecordingCanvas.cpp",
"RenderNode.cpp",
"RenderProperties.cpp",
- "ResourceCache.cpp",
"SkiaCanvas.cpp",
- "Snapshot.cpp",
"TreeInfo.cpp",
"VectorDrawable.cpp",
"protos/graphicsstats.proto",
@@ -308,8 +304,6 @@
"tests/unit/main.cpp",
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
- "tests/unit/CanvasStateTests.cpp",
- "tests/unit/ClipAreaTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
"tests/unit/FatVectorTests.cpp",
@@ -328,7 +322,6 @@
"tests/unit/SkiaPipelineTests.cpp",
"tests/unit/SkiaRenderPropertiesTests.cpp",
"tests/unit/SkiaCanvasTests.cpp",
- "tests/unit/SnapshotTests.cpp",
"tests/unit/StringUtilsTests.cpp",
"tests/unit/TestUtilsTests.cpp",
"tests/unit/ThreadBaseTests.cpp",
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
deleted file mode 100644
index d18c4ab..0000000
--- a/libs/hwui/CanvasState.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "CanvasState.h"
-#include "hwui/Canvas.h"
-#include "utils/MathUtils.h"
-
-namespace android {
-namespace uirenderer {
-
-CanvasState::CanvasState(CanvasStateClient& renderer)
- : mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {}
-
-CanvasState::~CanvasState() {
- // First call freeSnapshot on all but mFirstSnapshot
- // to invoke all the dtors
- freeAllSnapshots();
-
- // Now actually release the memory
- while (mSnapshotPool) {
- void* temp = mSnapshotPool;
- mSnapshotPool = mSnapshotPool->previous;
- free(temp);
- }
-}
-
-void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
- if (mWidth != viewportWidth || mHeight != viewportHeight) {
- mWidth = viewportWidth;
- mHeight = viewportHeight;
- mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
- mCanvas.onViewportInitialized();
- }
-
- freeAllSnapshots();
- mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
- mSnapshot->setRelativeLightCenter(Vector3());
- mSaveCount = 1;
-}
-
-void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft,
- float clipTop, float clipRight, float clipBottom,
- const Vector3& lightCenter) {
- if (mWidth != viewportWidth || mHeight != viewportHeight) {
- mWidth = viewportWidth;
- mHeight = viewportHeight;
- mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
- mCanvas.onViewportInitialized();
- }
-
- freeAllSnapshots();
- mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
- mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
- mSnapshot->fbo = mCanvas.getTargetFbo();
- mSnapshot->setRelativeLightCenter(lightCenter);
- mSaveCount = 1;
-}
-
-Snapshot* CanvasState::allocSnapshot(Snapshot* previous, int savecount) {
- void* memory;
- if (mSnapshotPool) {
- memory = mSnapshotPool;
- mSnapshotPool = mSnapshotPool->previous;
- mSnapshotPoolCount--;
- } else {
- memory = malloc(sizeof(Snapshot));
- }
- return new (memory) Snapshot(previous, savecount);
-}
-
-void CanvasState::freeSnapshot(Snapshot* snapshot) {
- snapshot->~Snapshot();
- // Arbitrary number, just don't let this grown unbounded
- if (mSnapshotPoolCount > 10) {
- free((void*)snapshot);
- } else {
- snapshot->previous = mSnapshotPool;
- mSnapshotPool = snapshot;
- mSnapshotPoolCount++;
- }
-}
-
-void CanvasState::freeAllSnapshots() {
- while (mSnapshot != &mFirstSnapshot) {
- Snapshot* temp = mSnapshot;
- mSnapshot = mSnapshot->previous;
- freeSnapshot(temp);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Save (layer)
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Guaranteed to save without side-effects
- *
- * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
- * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
- */
-int CanvasState::saveSnapshot(int flags) {
- mSnapshot = allocSnapshot(mSnapshot, flags);
- return mSaveCount++;
-}
-
-int CanvasState::save(int flags) {
- return saveSnapshot(flags);
-}
-
-/**
- * Guaranteed to restore without side-effects.
- */
-void CanvasState::restoreSnapshot() {
- Snapshot* toRemove = mSnapshot;
- Snapshot* toRestore = mSnapshot->previous;
-
- mSaveCount--;
- mSnapshot = toRestore;
-
- // subclass handles restore implementation
- mCanvas.onSnapshotRestored(*toRemove, *toRestore);
-
- freeSnapshot(toRemove);
-}
-
-void CanvasState::restore() {
- if (mSaveCount > 1) {
- restoreSnapshot();
- }
-}
-
-void CanvasState::restoreToCount(int saveCount) {
- if (saveCount < 1) saveCount = 1;
-
- while (mSaveCount > saveCount) {
- restoreSnapshot();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Matrix
-///////////////////////////////////////////////////////////////////////////////
-
-void CanvasState::getMatrix(SkMatrix* matrix) const {
- mSnapshot->transform->copyTo(*matrix);
-}
-
-void CanvasState::translate(float dx, float dy, float dz) {
- mSnapshot->transform->translate(dx, dy, dz);
-}
-
-void CanvasState::rotate(float degrees) {
- mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
-}
-
-void CanvasState::scale(float sx, float sy) {
- mSnapshot->transform->scale(sx, sy, 1.0f);
-}
-
-void CanvasState::skew(float sx, float sy) {
- mSnapshot->transform->skew(sx, sy);
-}
-
-void CanvasState::setMatrix(const SkMatrix& matrix) {
- mSnapshot->transform->load(matrix);
-}
-
-void CanvasState::setMatrix(const Matrix4& matrix) {
- *(mSnapshot->transform) = matrix;
-}
-
-void CanvasState::concatMatrix(const SkMatrix& matrix) {
- mat4 transform(matrix);
- mSnapshot->transform->multiply(transform);
-}
-
-void CanvasState::concatMatrix(const Matrix4& matrix) {
- mSnapshot->transform->multiply(matrix);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clip
-///////////////////////////////////////////////////////////////////////////////
-
-bool CanvasState::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
- mSnapshot->clip(Rect(left, top, right, bottom), op);
- return !mSnapshot->clipIsEmpty();
-}
-
-bool CanvasState::clipPath(const SkPath* path, SkClipOp op) {
- mSnapshot->clipPath(*path, op);
- return !mSnapshot->clipIsEmpty();
-}
-
-void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
- Rect bounds;
- float radius;
- if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
-
- bool outlineIsRounded = MathUtils::isPositive(radius);
- if (!outlineIsRounded || currentTransform()->isSimple()) {
- // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
- clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkClipOp::kIntersect);
- }
- if (outlineIsRounded) {
- setClippingRoundRect(allocator, bounds, radius, false);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Quick Rejection
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
- * the clipRect. Does not modify the scissor.
- *
- * @param clipRequired if not null, will be set to true if element intersects clip
- * (and wasn't rejected)
- *
- * @param snapOut if set, the geometry will be treated as having an AA ramp.
- * See Rect::snapGeometryToPixelBoundaries()
- */
-bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const {
- if (bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform()->mapRect(r);
- r.snapGeometryToPixelBoundaries(snapOut);
-
- Rect clipRect(currentRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- // clip is required if geometry intersects clip rect
- if (clipRequired) {
- *clipRequired = !clipRect.contains(r);
- }
-
- // round rect clip is required if RR clip exists, and geometry intersects its corners
- if (roundRectClipRequired) {
- *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr &&
- mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
- }
- return false;
-}
-
-bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const {
- if (bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform()->mapRect(r);
- r.roundOut(); // rounded out to be conservative
-
- Rect clipRect(currentRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- return false;
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
deleted file mode 100644
index 9ac35ff..0000000
--- a/libs/hwui/CanvasState.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Snapshot.h"
-
-#include <SkClipOp.h>
-#include <SkMatrix.h>
-#include <SkPath.h>
-#include <SkRegion.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Abstract base class for any class containing CanvasState.
- * Defines three mandatory callbacks.
- */
-class CanvasStateClient {
-public:
- CanvasStateClient() {}
- virtual ~CanvasStateClient() {}
-
- /**
- * Callback allowing embedder to take actions in the middle of a
- * setViewport() call.
- */
- virtual void onViewportInitialized() = 0;
-
- /**
- * Callback allowing embedder to take actions in the middle of a
- * restore() call. May be called several times sequentially.
- */
- virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
-
- /**
- * Allows subclasses to control what value is stored in snapshot's
- * fbo field in * initializeSaveStack.
- */
- virtual GLuint getTargetFbo() const = 0;
-
-}; // class CanvasStateClient
-
-/**
- * Implements Canvas state methods on behalf of Renderers.
- *
- * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
- * Renderer interface. Drawing and recording classes that include a CanvasState will have
- * different use cases:
- *
- * Drawing code maintaining canvas state (e.g. FrameBuilder) can query attributes (such as
- * transform) or hook into changes (e.g. save/restore) with minimal surface area for manipulating
- * the stack itself.
- *
- * Recording code maintaining canvas state (e.g. RecordingCanvas) can both record and pass
- * through state operations to CanvasState, so that not only will querying operations work
- * (getClip/Matrix), but so that quickRejection can also be used.
- */
-
-class CanvasState {
-public:
- explicit CanvasState(CanvasStateClient& renderer);
- ~CanvasState();
-
- /**
- * Initializes the first snapshot, computing the projection matrix,
- * and stores the dimensions of the render target.
- */
- void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
-
- /**
- * Initializes the first snapshot, computing the projection matrix,
- * and stores the dimensions of the render target.
- */
- void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop,
- float clipRight, float clipBottom, const Vector3& lightCenter);
-
- bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); }
-
- // Save (layer)
- int getSaveCount() const { return mSaveCount; }
- int save(int flags);
- void restore();
- void restoreToCount(int saveCount);
-
- // Save/Restore without side-effects
- int saveSnapshot(int flags);
- void restoreSnapshot();
-
- // Matrix
- void getMatrix(SkMatrix* outMatrix) const;
- void translate(float dx, float dy, float dz = 0.0f);
- void rotate(float degrees);
- void scale(float sx, float sy);
- void skew(float sx, float sy);
-
- void setMatrix(const SkMatrix& matrix);
- void setMatrix(const Matrix4& matrix); // internal only convenience method
- void concatMatrix(const SkMatrix& matrix);
- void concatMatrix(const Matrix4& matrix); // internal only convenience method
-
- // Clip
- const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
- const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
-
- bool quickRejectConservative(float left, float top, float right, float bottom) const;
-
- bool clipRect(float left, float top, float right, float bottom, SkClipOp op);
- bool clipPath(const SkPath* path, SkClipOp op);
-
- /**
- * Sets a "clipping outline", which is independent from the regular clip.
- * Currently only supports rectangles or rounded rectangles; passing in a
- * more complicated outline fails silently. Replaces any previous clipping
- * outline.
- */
- void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius,
- bool highPriority = true) {
- mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
- }
- void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); }
-
- /**
- * Returns true if drawing in the rectangle (left, top, right, bottom)
- * will be clipped out. Is conservative: might return false when subpixel-
- * perfect tests would return true.
- */
- bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const;
-
- void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
-
- inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
- inline const Rect& currentRenderTargetClip() const {
- return currentSnapshot()->getRenderTargetClip();
- }
- inline int currentFlags() const { return currentSnapshot()->flags; }
- const Vector3& currentLightCenter() const {
- return currentSnapshot()->getRelativeLightCenter();
- }
- int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
- int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
- int getWidth() const { return mWidth; }
- int getHeight() const { return mHeight; }
- bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
-
- inline const Snapshot* currentSnapshot() const { return mSnapshot; }
- inline Snapshot* writableSnapshot() { return mSnapshot; }
- inline const Snapshot* firstSnapshot() const { return &mFirstSnapshot; }
-
-private:
- Snapshot* allocSnapshot(Snapshot* previous, int savecount);
- void freeSnapshot(Snapshot* snapshot);
- void freeAllSnapshots();
-
- /// Dimensions of the drawing surface
- int mWidth, mHeight;
-
- /// Number of saved states
- int mSaveCount;
-
- /// Base state
- Snapshot mFirstSnapshot;
-
- /// Host providing callbacks
- CanvasStateClient& mCanvas;
-
- /// Current state
- Snapshot* mSnapshot;
-
- // Pool of allocated snapshots to re-use
- // NOTE: The dtors have already been invoked!
- Snapshot* mSnapshotPool = nullptr;
- int mSnapshotPoolCount = 0;
-
-}; // class CanvasState
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
deleted file mode 100644
index 27d93cf..0000000
--- a/libs/hwui/ClipArea.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ClipArea.h"
-
-#include "utils/LinearAllocator.h"
-
-#include <SkPath.h>
-#include <limits>
-#include <type_traits>
-
-namespace android {
-namespace uirenderer {
-
-static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
- Vertex v = {x, y};
- transform.mapPoint(v.x, v.y);
- transformedBounds.expandToCover(v.x, v.y);
-}
-
-Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
- const float kMinFloat = std::numeric_limits<float>::lowest();
- const float kMaxFloat = std::numeric_limits<float>::max();
- Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat};
- handlePoint(transformedBounds, transform, r.left, r.top);
- handlePoint(transformedBounds, transform, r.right, r.top);
- handlePoint(transformedBounds, transform, r.left, r.bottom);
- handlePoint(transformedBounds, transform, r.right, r.bottom);
- return transformedBounds;
-}
-
-void ClipBase::dump() const {
- ALOGD("mode %d" RECT_STRING, mode, RECT_ARGS(rect));
-}
-
-/*
- * TransformedRectangle
- */
-
-TransformedRectangle::TransformedRectangle() {}
-
-TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform)
- : mBounds(bounds), mTransform(transform) {}
-
-bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const {
- return mTransform == other.mTransform;
-}
-
-void TransformedRectangle::intersectWith(const TransformedRectangle& other) {
- mBounds.doIntersect(other.mBounds);
-}
-
-bool TransformedRectangle::isEmpty() const {
- return mBounds.isEmpty();
-}
-
-/*
- * RectangleList
- */
-
-RectangleList::RectangleList() : mTransformedRectanglesCount(0) {}
-
-bool RectangleList::isEmpty() const {
- if (mTransformedRectanglesCount < 1) {
- return true;
- }
-
- for (int i = 0; i < mTransformedRectanglesCount; i++) {
- if (mTransformedRectangles[i].isEmpty()) {
- return true;
- }
- }
- return false;
-}
-
-int RectangleList::getTransformedRectanglesCount() const {
- return mTransformedRectanglesCount;
-}
-
-const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
- return mTransformedRectangles[i];
-}
-
-void RectangleList::setEmpty() {
- mTransformedRectanglesCount = 0;
-}
-
-void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
- mTransformedRectanglesCount = 1;
- mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
-}
-
-bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) {
- TransformedRectangle newRectangle(bounds, transform);
-
- // Try to find a rectangle with a compatible transformation
- int index = 0;
- for (; index < mTransformedRectanglesCount; index++) {
- TransformedRectangle& tr(mTransformedRectangles[index]);
- if (tr.canSimplyIntersectWith(newRectangle)) {
- tr.intersectWith(newRectangle);
- return true;
- }
- }
-
- // Add it to the list if there is room
- if (index < kMaxTransformedRectangles) {
- mTransformedRectangles[index] = newRectangle;
- mTransformedRectanglesCount += 1;
- return true;
- }
-
- // This rectangle list is full
- return false;
-}
-
-Rect RectangleList::calculateBounds() const {
- Rect bounds;
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- const TransformedRectangle& tr(mTransformedRectangles[index]);
- if (index == 0) {
- bounds = tr.transformedBounds();
- } else {
- bounds.doIntersect(tr.transformedBounds());
- }
- }
- return bounds;
-}
-
-static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) {
- SkPath rectPath;
- SkPath rectPathTransformed;
- rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
- SkMatrix skTransform;
- transform.copyTo(skTransform);
- rectPath.transform(skTransform, &rectPathTransformed);
- return rectPathTransformed;
-}
-
-SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
- SkRegion rectangleListAsRegion;
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- const TransformedRectangle& tr(mTransformedRectangles[index]);
- SkPath rectPathTransformed =
- pathFromTransformedRectangle(tr.getBounds(), tr.getTransform());
- if (index == 0) {
- rectangleListAsRegion.setPath(rectPathTransformed, clip);
- } else {
- SkRegion rectRegion;
- rectRegion.setPath(rectPathTransformed, clip);
- rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
- }
- }
- return rectangleListAsRegion;
-}
-
-void RectangleList::transform(const Matrix4& transform) {
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- mTransformedRectangles[index].transform(transform);
- }
-}
-
-/*
- * ClipArea
- */
-
-ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {}
-
-/*
- * Interface
- */
-
-void ClipArea::setViewportDimensions(int width, int height) {
- mPostViewportClipObserved = false;
- mViewportBounds.set(0, 0, width, height);
- mClipRect = mViewportBounds;
-}
-
-void ClipArea::setEmpty() {
- onClipUpdated();
- mMode = ClipMode::Rectangle;
- mClipRect.setEmpty();
- mClipRegion.setEmpty();
- mRectangleList.setEmpty();
-}
-
-void ClipArea::setClip(float left, float top, float right, float bottom) {
- onClipUpdated();
- mMode = ClipMode::Rectangle;
- mClipRect.set(left, top, right, bottom);
- mClipRegion.setEmpty();
-}
-
-void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- switch (mMode) {
- case ClipMode::Rectangle:
- rectangleModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::RectangleList:
- rectangleListModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::Region:
- regionModeClipRectWithTransform(r, transform, op);
- break;
- }
-}
-
-void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- enterRegionMode();
- mClipRegion.op(region, op);
- onClipRegionUpdated();
-}
-
-void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- SkMatrix skTransform;
- transform->copyTo(skTransform);
- SkPath transformed;
- path.transform(skTransform, &transformed);
- SkRegion region;
- regionFromPath(transformed, region);
- enterRegionMode();
- mClipRegion.op(region, op);
- onClipRegionUpdated();
-}
-
-/*
- * Rectangle mode
- */
-
-void ClipArea::enterRectangleMode() {
- // Entering rectangle mode discards any
- // existing clipping information from the other modes.
- // The only way this occurs is by a clip setting operation.
- mMode = ClipMode::Rectangle;
-}
-
-void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
- mClipRect = r;
- transform->mapRect(mClipRect);
- return;
- } else if (op != SkRegion::kIntersect_Op) {
- enterRegionMode();
- regionModeClipRectWithTransform(r, transform, op);
- return;
- }
-
- if (transform->rectToRect()) {
- Rect transformed(r);
- transform->mapRect(transformed);
- mClipRect.doIntersect(transformed);
- return;
- }
-
- enterRectangleListMode();
- rectangleListModeClipRectWithTransform(r, transform, op);
-}
-
-/*
- * RectangleList mode implementation
- */
-
-void ClipArea::enterRectangleListMode() {
- // Is is only legal to enter rectangle list mode from
- // rectangle mode, since rectangle list mode cannot represent
- // all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == ClipMode::Rectangle);
- mMode = ClipMode::RectangleList;
- mRectangleList.set(mClipRect, Matrix4::identity());
-}
-
-void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) {
- enterRegionMode();
- regionModeClipRectWithTransform(r, transform, op);
- }
-}
-
-/*
- * Region mode implementation
- */
-
-void ClipArea::enterRegionMode() {
- ClipMode oldMode = mMode;
- mMode = ClipMode::Region;
- if (oldMode != ClipMode::Region) {
- if (oldMode == ClipMode::Rectangle) {
- mClipRegion.setRect(mClipRect.toSkIRect());
- } else {
- mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
- onClipRegionUpdated();
- }
- }
-}
-
-void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
- SkRegion transformedRectRegion;
- regionFromPath(transformedRect, transformedRectRegion);
- mClipRegion.op(transformedRectRegion, op);
- onClipRegionUpdated();
-}
-
-void ClipArea::onClipRegionUpdated() {
- if (!mClipRegion.isEmpty()) {
- mClipRect.set(mClipRegion.getBounds());
-
- if (mClipRegion.isRect()) {
- mClipRegion.setEmpty();
- enterRectangleMode();
- }
- } else {
- mClipRect.setEmpty();
- }
-}
-
-/**
- * Clip serialization
- */
-
-const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
- if (!mPostViewportClipObserved) {
- // Only initial clip-to-viewport observed, so no serialization of clip necessary
- return nullptr;
- }
-
- static_assert(std::is_trivially_destructible<Rect>::value,
- "expect Rect to be trivially destructible");
- static_assert(std::is_trivially_destructible<RectangleList>::value,
- "expect RectangleList to be trivially destructible");
-
- if (mLastSerialization == nullptr) {
- ClipBase* serialization = nullptr;
- switch (mMode) {
- case ClipMode::Rectangle:
- serialization = allocator.create<ClipRect>(mClipRect);
- break;
- case ClipMode::RectangleList:
- serialization = allocator.create<ClipRectList>(mRectangleList);
- serialization->rect = mRectangleList.calculateBounds();
- break;
- case ClipMode::Region:
- serialization = allocator.create<ClipRegion>(mClipRegion);
- serialization->rect.set(mClipRegion.getBounds());
- break;
- }
- serialization->intersectWithRoot = mReplaceOpObserved;
- // TODO: this is only done for draw time, should eventually avoid for record time
- serialization->rect.snapToPixelBoundaries();
- mLastSerialization = serialization;
- }
- return mLastSerialization;
-}
-
-inline static const RectangleList& getRectList(const ClipBase* scb) {
- return reinterpret_cast<const ClipRectList*>(scb)->rectList;
-}
-
-inline static const SkRegion& getRegion(const ClipBase* scb) {
- return reinterpret_cast<const ClipRegion*>(scb)->region;
-}
-
-// Conservative check for too many rectangles to fit in rectangle list.
-// For simplicity, doesn't account for rect merging
-static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
- int currentRectCount = clipArea.isRectangleList()
- ? clipArea.getRectangleList().getTransformedRectanglesCount()
- : 1;
- int recordedRectCount = (scb->mode == ClipMode::RectangleList)
- ? getRectList(scb).getTransformedRectanglesCount()
- : 1;
- return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
-}
-
-static const ClipRect sEmptyClipRect(Rect(0, 0));
-
-const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform) {
- // if no recordedClip passed, just serialize current state
- if (!recordedClip) return serializeClip(allocator);
-
- // if either is empty, clip is empty
- if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect;
-
- if (!mLastResolutionResult || recordedClip != mLastResolutionClip ||
- recordedClipTransform != mLastResolutionTransform) {
- mLastResolutionClip = recordedClip;
- mLastResolutionTransform = recordedClipTransform;
-
- if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle &&
- recordedClipTransform.rectToRect())) {
- // common case - result is a single rectangle
- auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
- recordedClipTransform.mapRect(rectClip->rect);
- rectClip->rect.doIntersect(mClipRect);
- rectClip->rect.snapToPixelBoundaries();
- mLastResolutionResult = rectClip;
- } else if (CC_UNLIKELY(mMode == ClipMode::Region ||
- recordedClip->mode == ClipMode::Region ||
- cannotFitInRectangleList(*this, recordedClip))) {
- // region case
- SkRegion other;
- switch (recordedClip->mode) {
- case ClipMode::Rectangle:
- if (CC_LIKELY(recordedClipTransform.rectToRect())) {
- // simple transform, skip creating SkPath
- Rect resultClip(recordedClip->rect);
- recordedClipTransform.mapRect(resultClip);
- other.setRect(resultClip.toSkIRect());
- } else {
- SkPath transformedRect = pathFromTransformedRectangle(
- recordedClip->rect, recordedClipTransform);
- other.setPath(transformedRect, createViewportRegion());
- }
- break;
- case ClipMode::RectangleList: {
- RectangleList transformedList(getRectList(recordedClip));
- transformedList.transform(recordedClipTransform);
- other = transformedList.convertToRegion(createViewportRegion());
- break;
- }
- case ClipMode::Region:
- other = getRegion(recordedClip);
- applyTransformToRegion(recordedClipTransform, &other);
- }
-
- ClipRegion* regionClip = allocator.create<ClipRegion>();
- switch (mMode) {
- case ClipMode::Rectangle:
- regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::RectangleList:
- regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
- other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::Region:
- regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
- break;
- }
- // Don't need to snap, since region's in int bounds
- regionClip->rect.set(regionClip->region.getBounds());
- mLastResolutionResult = regionClip;
- } else {
- auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
- auto&& rectList = rectListClip->rectList;
- if (mMode == ClipMode::Rectangle) {
- rectList.set(mClipRect, Matrix4::identity());
- }
-
- if (recordedClip->mode == ClipMode::Rectangle) {
- rectList.intersectWith(recordedClip->rect, recordedClipTransform);
- } else {
- const RectangleList& other = getRectList(recordedClip);
- for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
- auto&& tr = other.getTransformedRectangle(i);
- Matrix4 totalTransform(recordedClipTransform);
- totalTransform.multiply(tr.getTransform());
- rectList.intersectWith(tr.getBounds(), totalTransform);
- }
- }
- rectListClip->rect = rectList.calculateBounds();
- rectListClip->rect.snapToPixelBoundaries();
- mLastResolutionResult = rectListClip;
- }
- }
- return mLastResolutionResult;
-}
-
-void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
- if (!clip) return; // nothing to do
-
- if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
- clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
- } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
- auto&& rectList = getRectList(clip);
- for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
- auto&& tr = rectList.getTransformedRectangle(i);
- Matrix4 totalTransform(transform);
- totalTransform.multiply(tr.getTransform());
- clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
- }
- } else {
- SkRegion region(getRegion(clip));
- applyTransformToRegion(transform, ®ion);
- clipRegion(region, SkRegion::kIntersect_Op);
- }
-}
-
-void ClipArea::applyTransformToRegion(const Matrix4& transform, SkRegion* region) {
- if (transform.rectToRect() && !transform.isPureTranslate()) {
- // handle matrices with scale manually by mapping each rect
- SkRegion other;
- SkRegion::Iterator it(*region);
- while (!it.done()) {
- Rect rect(it.rect());
- transform.mapRect(rect);
- rect.snapGeometryToPixelBoundaries(true);
- other.op(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kUnion_Op);
- it.next();
- }
- region->swap(other);
- } else {
- // TODO: handle non-translate transforms properly!
- region->translate(transform.getTranslateX(), transform.getTranslateY());
- }
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
deleted file mode 100644
index a7a1180..0000000
--- a/libs/hwui/ClipArea.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-#ifndef CLIPAREA_H
-#define CLIPAREA_H
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "utils/Pair.h"
-
-#include <SkRegion.h>
-
-namespace android {
-namespace uirenderer {
-
-class LinearAllocator;
-
-Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
-
-class TransformedRectangle {
-public:
- TransformedRectangle();
- TransformedRectangle(const Rect& bounds, const Matrix4& transform);
-
- bool canSimplyIntersectWith(const TransformedRectangle& other) const;
- void intersectWith(const TransformedRectangle& other);
-
- bool isEmpty() const;
-
- const Rect& getBounds() const { return mBounds; }
-
- Rect transformedBounds() const {
- Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
- return transformedBounds;
- }
-
- const Matrix4& getTransform() const { return mTransform; }
-
- void transform(const Matrix4& transform) {
- Matrix4 t;
- t.loadMultiply(transform, mTransform);
- mTransform = t;
- }
-
-private:
- Rect mBounds;
- Matrix4 mTransform;
-};
-
-class RectangleList {
-public:
- RectangleList();
-
- bool isEmpty() const;
- int getTransformedRectanglesCount() const;
- const TransformedRectangle& getTransformedRectangle(int i) const;
-
- void setEmpty();
- void set(const Rect& bounds, const Matrix4& transform);
- bool intersectWith(const Rect& bounds, const Matrix4& transform);
- void transform(const Matrix4& transform);
-
- SkRegion convertToRegion(const SkRegion& clip) const;
- Rect calculateBounds() const;
-
- enum { kMaxTransformedRectangles = 5 };
-
-private:
- int mTransformedRectanglesCount;
- TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
-};
-
-enum class ClipMode {
- Rectangle,
- RectangleList,
-
- // region and path - intersected. if either is empty, don't use
- Region
-};
-
-struct ClipBase {
- explicit ClipBase(ClipMode mode) : mode(mode) {}
- explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {}
- const ClipMode mode;
- bool intersectWithRoot = false;
- // Bounds of the clipping area, used to define the scissor, and define which
- // portion of the stencil is updated/used
- Rect rect;
-
- void dump() const;
-};
-
-struct ClipRect : ClipBase {
- explicit ClipRect(const Rect& rect) : ClipBase(rect) {}
-};
-
-struct ClipRectList : ClipBase {
- explicit ClipRectList(const RectangleList& rectList)
- : ClipBase(ClipMode::RectangleList), rectList(rectList) {}
- RectangleList rectList;
-};
-
-struct ClipRegion : ClipBase {
- explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {}
- ClipRegion() : ClipBase(ClipMode::Region) {}
- SkRegion region;
-};
-
-class ClipArea {
-public:
- ClipArea();
-
- void setViewportDimensions(int width, int height);
-
- bool isEmpty() const { return mClipRect.isEmpty(); }
-
- void setEmpty();
- void setClip(float left, float top, float right, float bottom);
- void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
- void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op);
-
- const Rect& getClipRect() const { return mClipRect; }
-
- const SkRegion& getClipRegion() const { return mClipRegion; }
-
- const RectangleList& getRectangleList() const { return mRectangleList; }
-
- bool isRegion() const { return ClipMode::Region == mMode; }
-
- bool isSimple() const { return mMode == ClipMode::Rectangle; }
-
- bool isRectangleList() const { return mMode == ClipMode::RectangleList; }
-
- WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
- LinearAllocator& allocator, const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform);
- void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
-
- static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
-
-private:
- void enterRectangleMode();
- void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-
- void enterRectangleListMode();
- void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
-
- void enterRegionModeFromRectangleMode();
- void enterRegionModeFromRectangleListMode();
- void enterRegionMode();
- void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-
- void clipRegion(const SkRegion& region, SkRegion::Op op);
- void ensureClipRegion();
- void onClipRegionUpdated();
-
- // Called by every state modifying public method.
- void onClipUpdated() {
- mPostViewportClipObserved = true;
- mLastSerialization = nullptr;
- mLastResolutionResult = nullptr;
- }
-
- SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); }
-
- void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
- // TODO: this should not mask every path to the viewport - this makes it impossible to use
- // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
- pathAsRegion.setPath(path, createViewportRegion());
- }
-
- ClipMode mMode;
- bool mPostViewportClipObserved = false;
- bool mReplaceOpObserved = false;
-
- /**
- * If mLastSerialization is non-null, it represents an already serialized copy
- * of the current clip state. If null, it has not been computed.
- */
- const ClipBase* mLastSerialization = nullptr;
-
- /**
- * This pair of pointers is a single entry cache of most recently seen
- */
- const ClipBase* mLastResolutionResult = nullptr;
- const ClipBase* mLastResolutionClip = nullptr;
- Matrix4 mLastResolutionTransform;
-
- Rect mViewportBounds;
- Rect mClipRect;
- SkRegion mClipRegion;
- RectangleList mRectangleList;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* CLIPAREA_H_ */
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
deleted file mode 100644
index b424f97..0000000
--- a/libs/hwui/FloatColor.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-#ifndef FLOATCOLOR_H
-#define FLOATCOLOR_H
-
-#include "utils/Color.h"
-#include "utils/Macros.h"
-#include "utils/MathUtils.h"
-
-#include <stdint.h>
-
-namespace android {
-namespace uirenderer {
-
-struct FloatColor {
- // "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a pre-multiplied linear color
- // if linear blending is enabled. Otherwise, the color is stored as a pre-multiplied
- // gamma-encoded sRGB color
- void set(uint32_t color) {
- a = ((color >> 24) & 0xff) / 255.0f;
- r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
- g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
- b = a * EOCF(((color)&0xff) / 255.0f);
- }
-
- // "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a un-premultiplied linear color
- // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied
- // gamma-encoded sRGB color
- void setUnPreMultiplied(uint32_t color) {
- a = ((color >> 24) & 0xff) / 255.0f;
- r = EOCF(((color >> 16) & 0xff) / 255.0f);
- g = EOCF(((color >> 8) & 0xff) / 255.0f);
- b = EOCF(((color)&0xff) / 255.0f);
- }
-
- bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; }
-
- bool operator==(const FloatColor& other) const {
- return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) &&
- MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a);
- }
-
- bool operator!=(const FloatColor& other) const { return !(*this == other); }
-
- float r;
- float g;
- float b;
- float a;
-};
-
-REQUIRE_COMPATIBLE_LAYOUT(FloatColor);
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* FLOATCOLOR_H */
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
deleted file mode 100644
index 65bee47..0000000
--- a/libs/hwui/ResourceCache.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ResourceCache.h"
-
-namespace android {
-
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
-
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Resource cache
-///////////////////////////////////////////////////////////////////////////////
-
-void ResourceCache::logCache() {
- ALOGD("ResourceCache: cacheReport:");
- for (size_t i = 0; i < mCache->size(); ++i) {
- ResourceReference* ref = mCache->valueAt(i);
- ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i),
- mCache->valueAt(i));
- ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d", i,
- ref->refCount, ref->destroyed, ref->resourceType);
- }
-}
-
-ResourceCache::ResourceCache() {
- Mutex::Autolock _l(mLock);
- mCache = new KeyedVector<const void*, ResourceReference*>();
-}
-
-ResourceCache::~ResourceCache() {
- Mutex::Autolock _l(mLock);
- delete mCache;
-}
-
-void ResourceCache::lock() {
- mLock.lock();
-}
-
-void ResourceCache::unlock() {
- mLock.unlock();
-}
-
-void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
- Mutex::Autolock _l(mLock);
- incrementRefcountLocked(resource, resourceType);
-}
-
-void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
- incrementRefcount((void*)patchResource, kNinePatch);
-}
-
-void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr || mCache->size() == 0) {
- ref = new ResourceReference(resourceType);
- mCache->add(resource, ref);
- }
- ref->refCount++;
-}
-
-void ResourceCache::decrementRefcount(void* resource) {
- Mutex::Autolock _l(mLock);
- decrementRefcountLocked(resource);
-}
-
-void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
- decrementRefcount((void*)patchResource);
-}
-
-void ResourceCache::decrementRefcountLocked(void* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr) {
- // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
- return;
- }
- ref->refCount--;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
-void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
- decrementRefcountLocked((void*)patchResource);
-}
-
-void ResourceCache::destructor(Res_png_9patch* resource) {
- Mutex::Autolock _l(mLock);
- destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(Res_png_9patch* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr) {
- // If we're not tracking this resource, just delete it
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- delete[](int8_t*) resource;
- return;
- }
- ref->destroyed = true;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
-/**
- * This method should only be called while the mLock mutex is held (that mutex is grabbed
- * by the various destructor() and recycle() methods which call this method).
- */
-void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
- if (ref->destroyed) {
- switch (ref->resourceType) {
- case kNinePatch: {
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- int8_t* patch = (int8_t*)resource;
- delete[] patch;
- } break;
- }
- }
- mCache->removeItem(resource);
- delete ref;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
deleted file mode 100644
index fd3f9fd..0000000
--- a/libs/hwui/ResourceCache.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
-#define ANDROID_HWUI_RESOURCE_CACHE_H
-
-#include <cutils/compiler.h>
-
-#include <SkBitmap.h>
-#include <SkPixelRef.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
-
-#include <androidfw/ResourceTypes.h>
-
-namespace android {
-namespace uirenderer {
-
-class Layer;
-
-/**
- * Type of Resource being cached
- */
-enum ResourceType {
- kNinePatch,
-};
-
-class ResourceReference {
-public:
- explicit ResourceReference(ResourceType type) {
- refCount = 0;
- destroyed = false;
- resourceType = type;
- }
-
- int refCount;
- bool destroyed;
- ResourceType resourceType;
-};
-
-class ANDROID_API ResourceCache : public Singleton<ResourceCache> {
- ResourceCache();
- ~ResourceCache();
-
- friend class Singleton<ResourceCache>;
-
-public:
- /**
- * When using these two methods, make sure to only invoke the *Locked()
- * variants of increment/decrementRefcount(), recyle() and destructor()
- */
- void lock();
- void unlock();
-
- void incrementRefcount(const Res_png_9patch* resource);
-
- void decrementRefcount(const Res_png_9patch* resource);
-
- void decrementRefcountLocked(const Res_png_9patch* resource);
-
- void destructor(Res_png_9patch* resource);
-
- void destructorLocked(Res_png_9patch* resource);
-
-private:
- void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref);
-
- void incrementRefcount(void* resource, ResourceType resourceType);
- void incrementRefcountLocked(void* resource, ResourceType resourceType);
-
- void decrementRefcount(void* resource);
- void decrementRefcountLocked(void* resource);
-
- void logCache();
-
- /**
- * Used to increment, decrement, and destroy. Incrementing is generally accessed on the UI
- * thread, but destroying resources may be called from the GC thread, the finalizer thread,
- * or a reference queue finalization thread.
- */
- mutable Mutex mLock;
-
- KeyedVector<const void*, ResourceReference*>* mCache;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
deleted file mode 100644
index f1a1bef..0000000
--- a/libs/hwui/Snapshot.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Snapshot.h"
-
-#include "hwui/Canvas.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Constructors
-///////////////////////////////////////////////////////////////////////////////
-
-Snapshot::Snapshot()
- : flags(0)
- , previous(nullptr)
- , layer(nullptr)
- , fbo(0)
- , alpha(1.0f)
- , roundRectClipState(nullptr)
- , projectionPathMask(nullptr)
- , mClipArea(&mClipAreaRoot) {
- transform = &mTransformRoot;
- mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
-}
-
-/**
- * Copies the specified snapshot/ The specified snapshot is stored as
- * the previous snapshot.
- */
-Snapshot::Snapshot(Snapshot* s, int saveFlags)
- : flags(0)
- , previous(s)
- , layer(s->layer)
- , fbo(s->fbo)
- , alpha(s->alpha)
- , roundRectClipState(s->roundRectClipState)
- , projectionPathMask(s->projectionPathMask)
- , mClipArea(nullptr)
- , mViewportData(s->mViewportData)
- , mRelativeLightCenter(s->mRelativeLightCenter) {
- if (saveFlags & SaveFlags::Matrix) {
- mTransformRoot = *s->transform;
- transform = &mTransformRoot;
- } else {
- transform = s->transform;
- }
-
- if (saveFlags & SaveFlags::Clip) {
- mClipAreaRoot = s->getClipArea();
- mClipArea = &mClipAreaRoot;
- } else {
- mClipArea = s->mClipArea;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clipping
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::clip(const Rect& localClip, SkClipOp op) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
-}
-
-void Snapshot::clipPath(const SkPath& path, SkClipOp op) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->clipPathWithTransform(path, transform, static_cast<SkRegion::Op>(op));
-}
-
-void Snapshot::setClip(float left, float top, float right, float bottom) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->setClip(left, top, right, bottom);
-}
-
-bool Snapshot::hasPerspectiveTransform() const {
- return transform->isPerspective();
-}
-
-const Rect& Snapshot::getLocalClip() {
- mat4 inverse;
- inverse.loadInverse(*transform);
-
- mLocalClip.set(mClipArea->getClipRect());
- inverse.mapRect(mLocalClip);
-
- return mLocalClip;
-}
-
-void Snapshot::resetClip(float left, float top, float right, float bottom) {
- // TODO: This is incorrect, when we start rendering into a new layer,
- // we may have to modify the previous snapshot's clip rect and clip
- // region if the previous restore() call did not restore the clip
- mClipArea = &mClipAreaRoot;
- setClip(left, top, right, bottom);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clipping round rect
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
- bool highPriority) {
- if (bounds.isEmpty()) {
- mClipArea->setEmpty();
- return;
- }
-
- if (roundRectClipState && roundRectClipState->highPriority) {
- // ignore, don't replace, already have a high priority clip
- return;
- }
-
- RoundRectClipState* state = new (allocator) RoundRectClipState;
-
- state->highPriority = highPriority;
-
- // store the inverse drawing matrix
- Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
- roundRectDrawingMatrix.multiply(*transform);
- state->matrix.loadInverse(roundRectDrawingMatrix);
-
- // compute area under rounded corners - only draws overlapping these rects need to be clipped
- for (int i = 0; i < 4; i++) {
- state->dangerRects[i] = bounds;
- }
- state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
- state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
- state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
- state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
- for (int i = 0; i < 4; i++) {
- transform->mapRect(state->dangerRects[i]);
-
- // round danger rects out as though they are AA geometry (since they essentially are)
- state->dangerRects[i].snapGeometryToPixelBoundaries(true);
- }
-
- // store RR area
- state->innerRect = bounds;
- state->innerRect.inset(radius);
- state->radius = radius;
-
- // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
- roundRectClipState = state;
-}
-
-void Snapshot::setProjectionPathMask(const SkPath* path) {
- projectionPathMask = path;
-}
-
-static Snapshot* getClipRoot(Snapshot* target) {
- while (target->previous && target->previous->previous) {
- target = target->previous;
- }
- return target;
-}
-
-const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform) {
- auto target = this;
- if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
- // Clip must be intersected with root, instead of current clip.
- target = getClipRoot(this);
- }
-
- return target->mClipArea->serializeIntersectedClip(allocator, recordedClip,
- recordedClipTransform);
-}
-
-void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
- if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
- // current clip is being replaced, but must intersect with clip root
- *mClipArea = *(getClipRoot(this)->mClipArea);
- }
- mClipArea->applyClip(recordedClip, transform);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Queries
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::dump() const {
- ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous,
- getViewportHeight(), !mClipArea->isSimple());
- const Rect& clipRect(mClipArea->getClipRect());
- ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top,
- clipRect.right, clipRect.bottom, mClipArea->isSimple());
-
- ALOGD(" Transform (at %p):", transform);
- transform->dump();
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
deleted file mode 100644
index 655f819..0000000
--- a/libs/hwui/Snapshot.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/Region.h>
-#include <utils/LinearAllocator.h>
-#include <utils/RefBase.h>
-
-#include <SkClipOp.h>
-#include <SkRegion.h>
-
-#include "ClipArea.h"
-#include "Layer.h"
-#include "Matrix.h"
-#include "Outline.h"
-#include "Rect.h"
-#include "utils/Macros.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Temporary structure holding information for a single outline clip.
- *
- * These structures are treated as immutable once created, and only exist for a single frame, which
- * is why they may only be allocated with a LinearAllocator.
- */
-class RoundRectClipState {
-public:
- static void* operator new(size_t size) = delete;
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc<RoundRectClipState>(size);
- }
-
- bool areaRequiresRoundRectClip(const Rect& rect) const {
- return rect.intersects(dangerRects[0]) || rect.intersects(dangerRects[1]) ||
- rect.intersects(dangerRects[2]) || rect.intersects(dangerRects[3]);
- }
-
- bool highPriority;
- Matrix4 matrix;
- Rect dangerRects[4];
- Rect innerRect;
- float radius;
-};
-
-/**
- * A snapshot holds information about the current state of the rendering
- * surface. A snapshot is usually created whenever the user calls save()
- * and discarded when the user calls restore(). Once a snapshot is created,
- * it can hold information for deferred rendering.
- *
- * Each snapshot has a link to a previous snapshot, indicating the previous
- * state of the renderer.
- */
-class Snapshot {
-public:
- Snapshot();
- Snapshot(Snapshot* s, int saveFlags);
-
- /**
- * Various flags set on ::flags.
- */
- enum Flags {
- /**
- * Indicates that the clip region was modified. When this
- * snapshot is restored so must the clip.
- */
- kFlagClipSet = 0x1,
- /**
- * Indicates that this snapshot was created when saving
- * a new layer.
- */
- kFlagIsLayer = 0x2,
- /**
- * Indicates that this snapshot is a special type of layer
- * backed by an FBO. This flag only makes sense when the
- * flag kFlagIsLayer is also set.
- *
- * Viewport has been modified to fit the new Fbo, and must be
- * restored when this snapshot is restored.
- */
- kFlagIsFboLayer = 0x4,
- };
-
- /**
- * Modifies the current clip with the new clip rectangle and
- * the specified operation. The specified rectangle is transformed
- * by this snapshot's trasnformation.
- */
- void clip(const Rect& localClip, SkClipOp op);
-
- /**
- * Modifies the current clip with the new clip rectangle and
- * the specified operation. The specified rectangle is considered
- * already transformed.
- */
- void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect);
-
- /**
- * Modifies the current clip with the specified path and operation.
- */
- void clipPath(const SkPath& path, SkClipOp op);
-
- /**
- * Sets the current clip.
- */
- void setClip(float left, float top, float right, float bottom);
-
- /**
- * Returns the current clip in local coordinates. The clip rect is
- * transformed by the inverse transform matrix.
- */
- ANDROID_API const Rect& getLocalClip();
-
- /**
- * Returns the current clip in render target coordinates.
- */
- const Rect& getRenderTargetClip() const { return mClipArea->getClipRect(); }
-
- /*
- * Accessor functions so that the clip area can stay private
- */
- bool clipIsEmpty() const { return mClipArea->isEmpty(); }
- const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
- bool clipIsSimple() const { return mClipArea->isSimple(); }
- const ClipArea& getClipArea() const { return *mClipArea; }
- ClipArea& mutateClipArea() { return *mClipArea; }
-
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
- LinearAllocator& allocator, const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform);
- void applyClip(const ClipBase* clip, const Matrix4& transform);
-
- /**
- * Resets the clip to the specified rect.
- */
- void resetClip(float left, float top, float right, float bottom);
-
- void initializeViewport(int width, int height) {
- mViewportData.initialize(width, height);
- mClipAreaRoot.setViewportDimensions(width, height);
- }
-
- int getViewportWidth() const { return mViewportData.mWidth; }
- int getViewportHeight() const { return mViewportData.mHeight; }
- const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
-
- const Vector3& getRelativeLightCenter() const { return mRelativeLightCenter; }
- void setRelativeLightCenter(const Vector3& lightCenter) { mRelativeLightCenter = lightCenter; }
-
- /**
- * Sets (and replaces) the current clipping outline
- *
- * If the current round rect clip is high priority, the incoming clip is ignored.
- */
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
- bool highPriority);
-
- /**
- * Sets (and replaces) the current projection mask
- */
- void setProjectionPathMask(const SkPath* path);
-
- /**
- * Indicates whether the current transform has perspective components.
- */
- bool hasPerspectiveTransform() const;
-
- /**
- * Dirty flags.
- */
- int flags;
-
- /**
- * Previous snapshot.
- */
- Snapshot* previous;
-
- /**
- * A pointer to the currently active layer.
- *
- * This snapshot does not own the layer, this pointer must not be freed.
- */
- Layer* layer;
-
- /**
- * Target FBO used for rendering. Set to 0 when rendering directly
- * into the framebuffer.
- */
- GLuint fbo;
-
- /**
- * Local transformation. Holds the current translation, scale and
- * rotation values.
- *
- * This is a reference to a matrix owned by this snapshot or another
- * snapshot. This pointer must not be freed. See ::mTransformRoot.
- */
- mat4* transform;
-
- /**
- * Current alpha value. This value is 1 by default, but may be set by a DisplayList which
- * has translucent rendering in a non-overlapping View. This value will be used by
- * the renderer to set the alpha in the current color being used for ensuing drawing
- * operations. The value is inherited by child snapshots because the same value should
- * be applied to descendants of the current DisplayList (for example, a TextView contains
- * the base alpha value which should be applied to the child DisplayLists used for drawing
- * the actual text).
- */
- float alpha;
-
- /**
- * Current clipping round rect.
- *
- * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips,
- * never modified.
- */
- const RoundRectClipState* roundRectClipState;
-
- /**
- * Current projection masking path - used exclusively to mask projected, tessellated circles.
- */
- const SkPath* projectionPathMask;
-
- void dump() const;
-
-private:
- struct ViewportData {
- ViewportData() : mWidth(0), mHeight(0) {}
- void initialize(int width, int height) {
- mWidth = width;
- mHeight = height;
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
- }
-
- /*
- * Width and height of current viewport.
- *
- * The viewport is always defined to be (0, 0, width, height).
- */
- int mWidth;
- int mHeight;
- /**
- * Contains the current orthographic, projection matrix.
- */
- mat4 mOrthoMatrix;
- };
-
- mat4 mTransformRoot;
-
- ClipArea mClipAreaRoot;
- ClipArea* mClipArea;
- Rect mLocalClip;
-
- ViewportData mViewportData;
- Vector3 mRelativeLightCenter;
-
-}; // class Snapshot
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index a6aae55..f091277 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,7 +19,6 @@
#include "Vector.h"
-#include "FloatColor.h"
#include "utils/Macros.h"
namespace android {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index a00b8db..c5db861d 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -21,7 +21,6 @@
#include <Properties.h>
#include <Rect.h>
#include <RenderNode.h>
-#include <Snapshot.h>
#include <hwui/Bitmap.h>
#include <pipeline/skia/SkiaRecordingCanvas.h>
#include <private/hwui/DrawGlInfo.h>
@@ -141,14 +140,6 @@
return true;
}
- static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
- std::unique_ptr<Snapshot> snapshot(new Snapshot());
- // store clip first, so it isn't transformed
- snapshot->setClip(clip.left, clip.top, clip.right, clip.bottom);
- *(snapshot->transform) = transform;
- return snapshot;
- }
-
static sk_sp<Bitmap> createBitmap(int width, int height,
SkColorType colorType = kN32_SkColorType) {
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 9388c20..70423a7 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -16,7 +16,6 @@
#include <benchmark/benchmark.h>
-#include "CanvasState.h"
#include "DisplayList.h"
#include "hwui/Canvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
@@ -116,52 +115,6 @@
}
BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
-class NullClient : public CanvasStateClient {
- void onViewportInitialized() override {}
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
- GLuint getTargetFbo() const override { return 0; }
-};
-
-void BM_CanvasState_saverestore(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.save(SaveFlags::MatrixClip);
- state.save(SaveFlags::MatrixClip);
- benchmark::DoNotOptimize(&state);
- state.restore();
- state.restore();
- }
-}
-BENCHMARK(BM_CanvasState_saverestore);
-
-void BM_CanvasState_init(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- benchmark::DoNotOptimize(&state);
- }
-}
-BENCHMARK(BM_CanvasState_init);
-
-void BM_CanvasState_translate(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.translate(5, 5, 0);
- benchmark::DoNotOptimize(&state);
- state.translate(-5, -5, 0);
- }
-}
-BENCHMARK(BM_CanvasState_translate);
-
void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, [](auto& props, auto& canvas) {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
deleted file mode 100644
index 4c03811..0000000
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "CanvasState.h"
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "hwui/Canvas.h"
-#include "utils/LinearAllocator.h"
-
-#include <SkClipOp.h>
-#include <SkPath.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace uirenderer {
-
-class NullClient : public CanvasStateClient {
- void onViewportInitialized() override {}
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
- GLuint getTargetFbo() const override { return 0; }
-};
-
-static NullClient sNullClient;
-
-static bool approxEqual(const Matrix4& a, const Matrix4& b) {
- for (int i = 0; i < 16; i++) {
- if (!MathUtils::areEqual(a[i], b[i])) {
- return false;
- }
- }
- return true;
-}
-
-TEST(CanvasState, gettersAndSetters) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- ASSERT_EQ(state.getWidth(), 200);
- ASSERT_EQ(state.getHeight(), 200);
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 20, 0);
- state.setMatrix(simpleTranslate);
-
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
- ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- EXPECT_TRUE(state.clipIsSimple());
-}
-
-TEST(CanvasState, simpleClipping) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
-
- state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
-
- state.clipRect(50, 50, 150, 150, SkClipOp::kReplace_deprecated);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
-}
-
-TEST(CanvasState, complexClipping) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::MatrixClip);
- {
- // rotated clip causes complex clip
- state.rotate(10);
- EXPECT_TRUE(state.clipIsSimple());
- state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-
- state.save(SaveFlags::MatrixClip);
- {
- // subtracted clip causes complex clip
- EXPECT_TRUE(state.clipIsSimple());
- state.clipRect(50, 50, 150, 150, SkClipOp::kDifference);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-
- state.save(SaveFlags::MatrixClip);
- {
- // complex path causes complex clip
- SkPath path;
- path.addOval(SkRect::MakeWH(200, 200));
- EXPECT_TRUE(state.clipIsSimple());
- state.clipPath(&path, SkClipOp::kDifference);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-}
-
-TEST(CanvasState, saveAndRestore) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::Clip);
- {
- state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
- }
- state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Matrix);
- {
- state.translate(10, 10, 0);
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- }
- state.restore();
- EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
-}
-
-TEST(CanvasState, saveAndRestoreButNotTooMuch) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::Matrix); // NOTE: clip not saved
- {
- state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
- }
- state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Clip); // NOTE: matrix not saved
- {
- state.translate(10, 10, 0);
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- }
- state.restore();
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
-}
-}
-}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
deleted file mode 100644
index 450bb67..0000000
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <SkPath.h>
-#include <SkRegion.h>
-#include <gtest/gtest.h>
-
-#include "ClipArea.h"
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "utils/LinearAllocator.h"
-
-namespace android {
-namespace uirenderer {
-
-static Rect kViewportBounds(2048, 2048);
-
-static ClipArea createClipArea() {
- ClipArea area;
- area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight());
- return area;
-}
-
-TEST(TransformedRectangle, basics) {
- Rect r(0, 0, 100, 100);
- Matrix4 minus90;
- minus90.loadRotate(-90);
- minus90.mapRect(r);
- Rect r2(20, 40, 120, 60);
-
- Matrix4 m90;
- m90.loadRotate(90);
- TransformedRectangle tr(r, m90);
- EXPECT_TRUE(tr.canSimplyIntersectWith(tr));
-
- Matrix4 m0;
- TransformedRectangle tr0(r2, m0);
- EXPECT_FALSE(tr.canSimplyIntersectWith(tr0));
-
- Matrix4 m45;
- m45.loadRotate(45);
- TransformedRectangle tr2(r, m45);
- EXPECT_FALSE(tr2.canSimplyIntersectWith(tr));
-}
-
-TEST(RectangleList, basics) {
- RectangleList list;
- EXPECT_TRUE(list.isEmpty());
-
- Rect r(0, 0, 100, 100);
- Matrix4 m45;
- m45.loadRotate(45);
- list.set(r, m45);
- EXPECT_FALSE(list.isEmpty());
-
- Rect r2(20, 20, 200, 200);
- list.intersectWith(r2, m45);
- EXPECT_FALSE(list.isEmpty());
- EXPECT_EQ(1, list.getTransformedRectanglesCount());
-
- Rect r3(20, 20, 200, 200);
- Matrix4 m30;
- m30.loadRotate(30);
- list.intersectWith(r2, m30);
- EXPECT_FALSE(list.isEmpty());
- EXPECT_EQ(2, list.getTransformedRectanglesCount());
-
- SkRegion clip;
- clip.setRect(0, 0, 2000, 2000);
- SkRegion rgn(list.convertToRegion(clip));
- EXPECT_FALSE(rgn.isEmpty());
-}
-
-TEST(ClipArea, basics) {
- ClipArea area(createClipArea());
- EXPECT_FALSE(area.isEmpty());
-}
-
-TEST(ClipArea, paths) {
- ClipArea area(createClipArea());
- SkPath path;
- SkScalar r = 100;
- path.addCircle(r, r, r);
- area.clipPathWithTransform(path, &Matrix4::identity(), SkRegion::kIntersect_Op);
- EXPECT_FALSE(area.isEmpty());
- EXPECT_FALSE(area.isSimple());
- EXPECT_FALSE(area.isRectangleList());
-
- Rect clipRect(area.getClipRect());
- Rect expected(0, 0, r * 2, r * 2);
- EXPECT_EQ(expected, clipRect);
- SkRegion clipRegion(area.getClipRegion());
- auto skRect(clipRegion.getBounds());
- Rect regionBounds;
- regionBounds.set(skRect);
- EXPECT_EQ(expected, regionBounds);
-}
-
-TEST(ClipArea, replaceNegative) {
- ClipArea area(createClipArea());
- area.setClip(0, 0, 100, 100);
-
- Rect expected(-50, -50, 50, 50);
- area.clipRectWithTransform(expected, &Matrix4::identity(), SkRegion::kReplace_Op);
- EXPECT_EQ(expected, area.getClipRect());
-}
-
-TEST(ClipArea, serializeClip) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
-
- // unset clip
- EXPECT_EQ(nullptr, area.serializeClip(allocator));
-
- // rect clip
- area.setClip(0, 0, 200, 200);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
- ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
- EXPECT_EQ(Rect(200, 200), serializedClip->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-
- // rect list
- Matrix4 rotate;
- rotate.loadRotate(5.0f);
- area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
- ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
- auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
- EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
- EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-
- // region
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::Region, serializedClip->mode);
- ASSERT_TRUE(serializedClip->intersectWithRoot) << "Replace op, so expect intersectWithRoot";
- auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
- EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
- << "Clip region should be 200x200";
- EXPECT_EQ(Rect(200, 200), clipRegion->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-}
-
-TEST(ClipArea, serializeClip_pathIntersectWithRoot) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kIntersect_Op);
-
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- EXPECT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
-}
-
-TEST(ClipArea, serializeIntersectedClip) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
-
- // simple state;
- EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
- area.setClip(0, 0, 200, 200);
- {
- auto origRectClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, origRectClip);
- EXPECT_EQ(origRectClip,
- area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
- }
-
- // rect
- {
- ClipRect recordedClip(Rect(100, 100));
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3, 1);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 200, 200), resolvedClip->rect);
-
- EXPECT_EQ(resolvedClip,
- area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
- << "Must return previous serialization, since input is same";
-
- ClipRect recordedClip2(Rect(100, 100));
- EXPECT_NE(resolvedClip,
- area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
- << "Shouldn't return previous serialization, since matrix location is different";
- }
-
- // rect list
- Matrix4 rotate;
- rotate.loadRotate(2.0f);
- area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
- {
- ClipRect recordedClip(Rect(100, 100));
- auto resolvedClip =
- area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
- auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
- EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
- }
-
- // region
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
- {
- SkPath ovalPath;
- ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
-
- ClipRegion recordedClip;
- recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
- recordedClip.rect = Rect(200, 200);
-
- Matrix4 translate10x20;
- translate10x20.loadTranslate(10, 20, 0);
- auto resolvedClip = area.serializeIntersectedClip(
- allocator, &recordedClip,
- translate10x20); // Note: only translate for now, others not handled correctly
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
- auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
- EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
- }
-}
-
-TEST(ClipArea, serializeIntersectedClip_snap) {
- ClipArea area(createClipArea());
- area.setClip(100.2, 100.4, 500.6, 500.8);
- LinearAllocator allocator;
-
- {
- // no recorded clip case
- auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity());
- EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect);
- }
- {
- // recorded clip case
- ClipRect recordedClip(Rect(100.12, 100.74));
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3,
- 1); // recorded clip will have non-int coords, even after transform
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
- ASSERT_NE(nullptr, resolvedClip);
- EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect);
- }
-}
-
-TEST(ClipArea, serializeIntersectedClip_scale) {
- ClipArea area(createClipArea());
- area.setClip(0, 0, 400, 400);
- LinearAllocator allocator;
-
- SkPath circlePath;
- circlePath.addCircle(50, 50, 50);
-
- ClipRegion recordedClip;
- recordedClip.region.setPath(circlePath, SkRegion(SkIRect::MakeWH(100, 100)));
- recordedClip.rect = Rect(100, 100);
-
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 2, 1);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
-
- ASSERT_NE(nullptr, resolvedClip);
- EXPECT_EQ(ClipMode::Region, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 300, 300), resolvedClip->rect);
- auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
- EXPECT_EQ(SkIRect::MakeLTRB(100, 100, 300, 300), clipRegion->region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_identity) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- ClipArea::applyTransformToRegion(Matrix4::identity(), ®ion);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(1, 2, 3, 4), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_translate) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadTranslate(10, 20, 0);
- ClipArea::applyTransformToRegion(transform, ®ion);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(11, 22, 13, 24), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_scale) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadScale(2, 3, 1);
- ClipArea::applyTransformToRegion(transform, ®ion);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(2, 6, 6, 12), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_translateScale) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.translate(10, 20);
- transform.scale(2, 3, 1);
- ClipArea::applyTransformToRegion(transform, ®ion);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(12, 26, 16, 32), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_rotate90) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadRotate(90);
- ClipArea::applyTransformToRegion(transform, ®ion);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 2926ef3..2c73940 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -32,6 +32,7 @@
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
using namespace android;
using namespace android::uirenderer;
diff --git a/libs/hwui/tests/unit/SnapshotTests.cpp b/libs/hwui/tests/unit/SnapshotTests.cpp
deleted file mode 100644
index 9d673c8..0000000
--- a/libs/hwui/tests/unit/SnapshotTests.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <Snapshot.h>
-
-#include <tests/common/TestUtils.h>
-
-using namespace android::uirenderer;
-
-TEST(Snapshot, serializeIntersectedClip) {
- auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100));
- auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90));
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- root->previous = actualRoot.get();
- child->previous = root.get();
-
- LinearAllocator allocator;
- ClipRect rect(Rect(0, 0, 75, 75));
- {
- auto intersectWithChild =
- child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
- ASSERT_NE(nullptr, intersectWithChild);
- EXPECT_EQ(Rect(50, 50, 75, 75), intersectWithChild->rect) << "Expect intersect with child";
- }
-
- rect.intersectWithRoot = true;
- {
- auto intersectWithRoot =
- child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
- ASSERT_NE(nullptr, intersectWithRoot);
- EXPECT_EQ(Rect(10, 10, 75, 75), intersectWithRoot->rect) << "Expect intersect with root";
- }
-}
-
-TEST(Snapshot, applyClip) {
- auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100));
- auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90));
- root->previous = actualRoot.get();
-
- ClipRect rect(Rect(0, 0, 75, 75));
- {
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- child->previous = root.get();
- child->applyClip(&rect, Matrix4::identity());
-
- EXPECT_TRUE(child->getClipArea().isSimple());
- EXPECT_EQ(Rect(50, 50, 75, 75), child->getRenderTargetClip());
- }
-
- {
- rect.intersectWithRoot = true;
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- child->previous = root.get();
- child->applyClip(&rect, Matrix4::identity());
-
- EXPECT_TRUE(child->getClipArea().isSimple());
- EXPECT_EQ(Rect(10, 10, 75, 75), child->getRenderTargetClip());
- }
-}
diff --git a/media/OWNERS b/media/OWNERS
index 1ae2a7b..0abf9ae 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -9,4 +9,4 @@
wjia@google.com
jaewan@google.com
chz@google.com
-
+dwkang@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c074cce..e8c97bc 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3942,18 +3942,31 @@
}
/**
- * Indicate Hearing Aid connection state change.
+ * Indicate Hearing Aid connection state change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
* @param device Bluetooth device connected/disconnected
* @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param musicDevice Default get system volume for the connecting device.
+ * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
+ * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * @return a delay in ms that the caller should wait before broadcasting
+ * BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED intent.
* {@hide}
*/
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) {
+ public int setBluetoothHearingAidDeviceConnectionState(
+ BluetoothDevice device, int state, boolean suppressNoisyIntent,
+ int musicDevice) {
final IAudioService service = getService();
+ int delay = 0;
try {
- service.setHearingAidDeviceConnectionState(device, state);
+ delay = service.setBluetoothHearingAidDeviceConnectionState(device,
+ state, suppressNoisyIntent, musicDevice);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ return delay;
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 569db16..abd6411 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -151,8 +151,6 @@
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
- void setHearingAidDeviceConnectionState(in BluetoothDevice device, int state);
-
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
@@ -210,6 +208,9 @@
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+ int setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
+ int state, boolean suppressNoisyIntent, int musicDevice);
+
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6d122d7..ee12b91 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1192,15 +1192,17 @@
public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5;
/**
- * The maximum security level supported by the device. This is the default
- * security level when a session is opened.
+ * Indicates that the maximum security level supported by the device should
+ * be used when opening a session. This is the default security level
+ * selected when a session is opened.
* @hide
*/
public static final int SECURITY_LEVEL_MAX = 6;
/**
- * The maximum security level supported by the device. This is the default
- * security level when a session is opened.
+ * Returns a value that may be passed as a parameter to {@link #openSession(int)}
+ * requesting that the session be opened at the maximum security level of
+ * the device.
*/
public static final int getMaxSecurityLevel() {
return SECURITY_LEVEL_MAX;
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 5adbc15..71df7dc 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -682,7 +682,9 @@
case DataSourceDesc.TYPE_CALLBACK:
handleDataSource(isCurrent,
srcId,
- dsd.getMedia2DataSource());
+ dsd.getMedia2DataSource(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
case DataSourceDesc.TYPE_FD:
@@ -690,7 +692,9 @@
srcId,
dsd.getFileDescriptor(),
dsd.getFileDescriptorOffset(),
- dsd.getFileDescriptorLength());
+ dsd.getFileDescriptorLength(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
case DataSourceDesc.TYPE_URI:
@@ -699,7 +703,9 @@
dsd.getUriContext(),
dsd.getUri(),
dsd.getUriHeaders(),
- dsd.getUriCookies());
+ dsd.getUriCookies(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
default:
@@ -729,62 +735,77 @@
private void handleDataSource(
boolean isCurrent, long srcId,
@NonNull Context context, @NonNull Uri uri,
- @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
+ @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
- // The context and URI usually belong to the calling user. Get a resolver for that user
- // and strip out the userId from the URI if present.
+ // The context and URI usually belong to the calling user. Get a resolver for that user.
final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
- final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
- handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
+ handleDataSource(isCurrent, srcId, uri.getPath(), null, null, startPos, endPos);
return;
}
- AssetFileDescriptor afd = null;
+ final int ringToneType = RingtoneManager.getDefaultType(uri);
try {
+ AssetFileDescriptor afd;
// Try requested Uri locally first
- if (ContentResolver.SCHEME_CONTENT.equals(scheme)
- && Settings.AUTHORITY.equals(authority)) {
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme) && ringToneType != -1) {
afd = RingtoneManager.openDefaultRingtoneUri(context, uri);
+ if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
+ return;
+ }
+ final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(
+ context, ringToneType);
+ afd = resolver.openAssetFileDescriptor(actualUri, "r");
} else {
afd = resolver.openAssetFileDescriptor(uri, "r");
}
- if (afd != null) {
- handleDataSource(isCurrent, srcId, afd);
+ if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
return;
}
} catch (NullPointerException | SecurityException | IOException ex) {
Log.w(TAG, "Couldn't open " + uri + ": " + ex);
// Fallback to media server
+ }
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies, startPos, endPos);
+ }
+
+ private boolean attemptDataSource(boolean isCurrent, long srcId, AssetFileDescriptor afd,
+ long startPos, long endPos) throws IOException {
+ try {
+ if (afd.getDeclaredLength() < 0) {
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ 0,
+ DataSourceDesc.LONG_MAX,
+ startPos,
+ endPos);
+ } else {
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ afd.getStartOffset(),
+ afd.getDeclaredLength(),
+ startPos,
+ endPos);
+ }
+ return true;
+ } catch (NullPointerException | SecurityException | IOException ex) {
+ Log.w(TAG, "Couldn't open srcId:" + srcId + ": " + ex);
+ return false;
} finally {
if (afd != null) {
afd.close();
}
}
- handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
- }
-
- private void handleDataSource(boolean isCurrent, long srcId, AssetFileDescriptor afd)
- throws IOException {
- if (afd.getDeclaredLength() < 0) {
- handleDataSource(isCurrent,
- srcId,
- afd.getFileDescriptor(),
- 0,
- DataSourceDesc.LONG_MAX);
- } else {
- handleDataSource(isCurrent,
- srcId,
- afd.getFileDescriptor(),
- afd.getStartOffset(),
- afd.getDeclaredLength());
- }
}
private void handleDataSource(
boolean isCurrent, long srcId,
- String path, Map<String, String> headers, List<HttpCookie> cookies)
+ String path, Map<String, String> headers, List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
String[] keys = null;
String[] values = null;
@@ -800,11 +821,12 @@
++i;
}
}
- handleDataSource(isCurrent, srcId, path, keys, values, cookies);
+ handleDataSource(isCurrent, srcId, path, keys, values, cookies, startPos, endPos);
}
private void handleDataSource(boolean isCurrent, long srcId,
- String path, String[] keys, String[] values, List<HttpCookie> cookies)
+ String path, String[] keys, String[] values, List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
@@ -818,7 +840,9 @@
Media2HTTPService.createHTTPService(path, cookies),
path,
keys,
- values);
+ values,
+ startPos,
+ endPos);
return;
}
@@ -826,7 +850,7 @@
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
- handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX, startPos, endPos);
is.close();
} else {
throw new IOException("handleDataSource failed.");
@@ -835,7 +859,8 @@
private native void nativeHandleDataSourceUrl(
boolean isCurrent, long srcId,
- Media2HTTPService httpService, String path, String[] keys, String[] values)
+ Media2HTTPService httpService, String path, String[] keys, String[] values,
+ long startPos, long endPos)
throws IOException;
/**
@@ -849,23 +874,27 @@
*/
private void handleDataSource(
boolean isCurrent, long srcId,
- FileDescriptor fd, long offset, long length) throws IOException {
- nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
+ FileDescriptor fd, long offset, long length,
+ long startPos, long endPos) throws IOException {
+ nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length, startPos, endPos);
}
private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
- FileDescriptor fd, long offset, long length) throws IOException;
+ FileDescriptor fd, long offset, long length,
+ long startPos, long endPos) throws IOException;
/**
* @throws IllegalStateException if it is called in an invalid state
* @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
*/
- private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
- nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
+ private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource,
+ long startPos, long endPos) {
+ nativeHandleDataSourceCallback(isCurrent, srcId, dataSource, startPos, endPos);
}
private native void nativeHandleDataSourceCallback(
- boolean isCurrent, long srcId, Media2DataSource dataSource);
+ boolean isCurrent, long srcId, Media2DataSource dataSource,
+ long startPos, long endPos);
/**
* @return true if there is a next data source, false otherwise.
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 352df81..61c28ed 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -283,7 +283,8 @@
static void
android_media_MediaPlayer2_handleDataSourceUrl(
JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
- jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values) {
+ jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values,
+ jlong startPos, jlong endPos) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
@@ -300,7 +301,8 @@
if (tmp == NULL) { // Out of memory
return;
}
- ALOGV("handleDataSourceUrl: path %s, srcId %lld", tmp, (long long)srcId);
+ ALOGV("handleDataSourceUrl: path %s, srcId %lld, start %lld, end %lld",
+ tmp, (long long)srcId, (long long)startPos, (long long)endPos);
if (strncmp(tmp, "content://", 10) == 0) {
ALOGE("handleDataSourceUrl: content scheme is not supported in native code");
@@ -313,6 +315,8 @@
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_URL;
dsd->mUrl = tmp;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
env->ReleaseStringUTFChars(path, tmp);
tmp = NULL;
@@ -341,9 +345,9 @@
static void
android_media_MediaPlayer2_handleDataSourceFD(
- JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
- jobject fileDescriptor, jlong offset, jlong length)
-{
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject fileDescriptor, jlong offset, jlong length,
+ jlong startPos, jlong endPos) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -355,8 +359,10 @@
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
- (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+ ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld, "
+ "start=%lld, end=%lld",
+ (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length,
+ (long long)startPos, (long long)endPos);
struct stat sb;
int ret = fstat(fd, &sb);
@@ -389,6 +395,8 @@
dsd->mFD = fd;
dsd->mFDOffset = offset;
dsd->mFDLength = length;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
status_t err;
if (isCurrent) {
@@ -402,7 +410,8 @@
static void
android_media_MediaPlayer2_handleDataSourceCallback(
- JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource)
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource,
+ jlong startPos, jlong endPos)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -419,6 +428,8 @@
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_CALLBACK;
dsd->mCallbackSource = callbackDataSource;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
status_t err;
if (isCurrent) {
@@ -1442,17 +1453,17 @@
{
"nativeHandleDataSourceUrl",
"(ZJLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
- "[Ljava/lang/String;)V",
+ "[Ljava/lang/String;JJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceUrl
},
{
"nativeHandleDataSourceFD",
- "(ZJLjava/io/FileDescriptor;JJ)V",
+ "(ZJLjava/io/FileDescriptor;JJJJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceFD
},
{
"nativeHandleDataSourceCallback",
- "(ZJLandroid/media/Media2DataSource;)V",
+ "(ZJLandroid/media/Media2DataSource;JJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceCallback
},
{"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
diff --git a/opengl/java/android/opengl/EGL15.java b/opengl/java/android/opengl/EGL15.java
new file mode 100644
index 0000000..9aae6ad
--- /dev/null
+++ b/opengl/java/android/opengl/EGL15.java
@@ -0,0 +1,149 @@
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * EGL 1.5
+ *
+ */
+public class EGL15 {
+
+ public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
+ public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
+ public static final int EGL_OPENGL_ES3_BIT = 0x00000040;
+ public static final int EGL_SYNC_FLUSH_COMMANDS_BIT = 0x0001;
+ public static final int EGL_GL_COLORSPACE_SRGB = 0x3089;
+ public static final int EGL_GL_COLORSPACE_LINEAR = 0x308A;
+ public static final int EGL_CONTEXT_MAJOR_VERSION = 0x3098;
+ public static final int EGL_CL_EVENT_HANDLE = 0x309C;
+ public static final int EGL_GL_COLORSPACE = 0x309D;
+ public static final int EGL_GL_TEXTURE_2D = 0x30B1;
+ public static final int EGL_GL_TEXTURE_3D = 0x30B2;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x30B3;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x30B4;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x30B5;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x30B6;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x30B7;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x30B8;
+ public static final int EGL_GL_RENDERBUFFER = 0x30B9;
+ public static final int EGL_GL_TEXTURE_LEVEL = 0x30BC;
+ public static final int EGL_GL_TEXTURE_ZOFFSET = 0x30BD;
+ public static final int EGL_IMAGE_PRESERVED = 0x30D2;
+ public static final int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 0x30F0;
+ public static final int EGL_SYNC_STATUS = 0x30F1;
+ public static final int EGL_SIGNALED = 0x30F2;
+ public static final int EGL_UNSIGNALED = 0x30F3;
+ public static final int EGL_TIMEOUT_EXPIRED = 0x30F5;
+ public static final int EGL_CONDITION_SATISFIED = 0x30F6;
+ public static final int EGL_SYNC_TYPE = 0x30F7;
+ public static final int EGL_SYNC_CONDITION = 0x30F8;
+ public static final int EGL_SYNC_FENCE = 0x30F9;
+ public static final int EGL_CONTEXT_MINOR_VERSION = 0x30FB;
+ public static final int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
+ public static final int EGL_SYNC_CL_EVENT = 0x30FE;
+ public static final int EGL_SYNC_CL_EVENT_COMPLETE = 0x30FF;
+ public static final int EGL_CONTEXT_OPENGL_DEBUG = 0x31B0;
+ public static final int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1;
+ public static final int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2;
+ public static final int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD;
+ public static final int EGL_NO_RESET_NOTIFICATION = 0x31BE;
+ public static final int EGL_LOSE_CONTEXT_ON_RESET = 0x31BF;
+ public static final int EGL_PLATFORM_ANDROID_KHR = 0x3141;
+ public static final long EGL_FOREVER = 0xFFFFFFFFFFFFFFFFL;
+ public static final EGLImage EGL_NO_IMAGE = null;
+ public static final EGLSync EGL_NO_SYNC = null;
+ public static final EGLContext EGL_NO_CONTEXT = null;
+ public static final EGLDisplay EGL_NO_DISPLAY = null;
+ public static final EGLSurface EGL_NO_SURFACE = null;
+
+ native private static void _nativeClassInit();
+ static {
+ _nativeClassInit();
+ }
+ // C function EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list )
+
+ public static native EGLSync eglCreateSync(
+ EGLDisplay dpy,
+ int type,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync )
+
+ public static native boolean eglDestroySync(
+ EGLDisplay dpy,
+ EGLSync sync
+ );
+
+ // C function EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout )
+
+ public static native int eglClientWaitSync(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int flags,
+ long timeout
+ );
+
+ // C function EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
+
+ public static native boolean eglGetSyncAttrib(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int attribute,
+ long[] value,
+ int offset
+ );
+
+ // C function EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
+
+ public static native EGLDisplay eglGetPlatformDisplay(
+ int platform,
+ long native_display,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list )
+
+ public static native EGLSurface eglCreatePlatformWindowSurface(
+ EGLDisplay dpy,
+ EGLConfig config,
+ java.nio.Buffer native_window,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list )
+
+ public static native EGLSurface eglCreatePlatformPixmapSurface(
+ EGLDisplay dpy,
+ EGLConfig config,
+ java.nio.Buffer native_pixmap,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags )
+
+ public static native boolean eglWaitSync(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int flags
+ );
+
+}
diff --git a/opengl/java/android/opengl/EGLImage.java b/opengl/java/android/opengl/EGLImage.java
new file mode 100644
index 0000000..731ce72
--- /dev/null
+++ b/opengl/java/android/opengl/EGLImage.java
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * Wrapper class for native EGLImage objects.
+ *
+ */
+public class EGLImage extends EGLObjectHandle {
+ private EGLImage(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLImage)) return false;
+
+ EGLImage that = (EGLImage) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/opengl/java/android/opengl/EGLSync.java b/opengl/java/android/opengl/EGLSync.java
new file mode 100644
index 0000000..472f9e7
--- /dev/null
+++ b/opengl/java/android/opengl/EGLSync.java
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.opengl;
+
+/**
+ * Wrapper class for native EGLSync objects.
+ *
+ */
+public class EGLSync extends EGLObjectHandle {
+ private EGLSync(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLSync)) return false;
+
+ EGLSync that = (EGLSync) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index d60dbe7..5161344 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -2,16 +2,14 @@
name: "SettingsLib",
- libs: [
+ static_libs: [
"androidx.annotation_annotation",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
"androidx.preference_preference",
"androidx.appcompat_appcompat",
"androidx.lifecycle_lifecycle-runtime",
- ],
- static_libs: [
"SettingsLibHelpUtils",
"SettingsLibRestrictedLockUtils",
"SettingsLibAppPreference",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 99a2cdc..80f3506 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -284,8 +284,8 @@
super.onViewCreated(view, savedInstanceState);
mNavigationBarView = (NavigationBarView) view;
- mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setComponents(mStatusBar.getPanel());
+ mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
if (savedInstanceState != null) {
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 980ba87..e92656ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -60,7 +60,6 @@
import com.android.systemui.Interpolators;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
@@ -71,7 +70,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -140,6 +138,7 @@
private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
private final ContextualButtonGroup mContextualButtonGroup;
private Configuration mConfiguration;
+ private Configuration mTmpLastConfiguration;
private NavigationBarInflaterView mNavigationInflaterView;
private RecentsOnboarding mRecentsOnboarding;
@@ -286,6 +285,7 @@
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mConfiguration = new Configuration();
+ mTmpLastConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
mScreenPinningNotify = new ScreenPinningNotify(mContext);
@@ -445,13 +445,13 @@
}
private void reloadNavIcons() {
- updateIcons(Configuration.EMPTY, mConfiguration);
+ updateIcons(Configuration.EMPTY);
}
- private void updateIcons(Configuration oldConfig, Configuration newConfig) {
- final boolean orientationChange = oldConfig.orientation != newConfig.orientation;
- final boolean densityChange = oldConfig.densityDpi != newConfig.densityDpi;
- final boolean dirChange = oldConfig.getLayoutDirection() != newConfig.getLayoutDirection();
+ private void updateIcons(Configuration oldConfig) {
+ final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
+ final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
+ final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
if (orientationChange || densityChange) {
mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
@@ -485,7 +485,7 @@
private void orientBackButton(KeyButtonDrawable drawable) {
final boolean useAltBack =
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- final boolean isRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
float degrees = useAltBack
? (isRtl ? 270 : -90)
: (isRtl ? 180 : 0);
@@ -946,26 +946,27 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- boolean uiCarModeChanged = updateCarMode(newConfig);
+ mTmpLastConfiguration.updateFrom(mConfiguration);
+ mConfiguration.updateFrom(newConfig);
+ boolean uiCarModeChanged = updateCarMode();
updateTaskSwitchHelper();
- updateIcons(mConfiguration, newConfig);
+ updateIcons(mTmpLastConfiguration);
updateRecentsIcon();
- mRecentsOnboarding.onConfigurationChanged(newConfig);
- if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi
- || mConfiguration.getLayoutDirection() != newConfig.getLayoutDirection()) {
+ mRecentsOnboarding.onConfigurationChanged(mConfiguration);
+ if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
+ || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
// If car mode or density changes, we need to reset the icons.
updateNavButtonIcons();
}
- mConfiguration.updateFrom(newConfig);
}
/**
* If the configuration changed, update the carmode and return that it was updated.
*/
- private boolean updateCarMode(Configuration newConfig) {
+ private boolean updateCarMode() {
boolean uiCarModeChanged = false;
- if (newConfig != null) {
- int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
+ if (mConfiguration != null) {
+ int uiMode = mConfiguration.uiMode & Configuration.UI_MODE_TYPE_MASK;
final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
if (isCarMode != mInCarMode) {
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 3bdd601..cc9adb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5277,8 +5277,7 @@
(Runnable saveImportance, StatusBarNotification sbn) -> {
// If the user has security enabled, show challenge if the setting is changed.
if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
- && (mState == StatusBarState.KEYGUARD ||
- mState == StatusBarState.SHADE_LOCKED)) {
+ && mKeyguardManager.isKeyguardLocked()) {
onLockedNotificationImportanceChange(() -> {
saveImportance.run();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 24a28cb..70a3589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -461,6 +461,8 @@
MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.handleBroadcast(intent);
}
+ mConfig = Config.readConfig(mContext);
+ mReceiverHandler.post(this::handleConfigurationChanged);
break;
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
@@ -1042,18 +1044,23 @@
config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
config.alwaysShowCdmaRssi =
res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
- config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
config.hspaDataDistinguishable =
res.getBoolean(R.bool.config_hspa_data_distinguishable);
- config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
config.inflateSignalStrengths = res.getBoolean(R.bool.config_inflateSignalStrength);
CarrierConfigManager configMgr = (CarrierConfigManager)
context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle b = configMgr.getConfig();
+ // Handle specific carrier config values for the default data SIM
+ int defaultDataSubId = SubscriptionManager.from(context)
+ .getDefaultDataSubscriptionId();
+ PersistableBundle b = configMgr.getConfigForSubId(defaultDataSubId);
if (b != null) {
config.alwaysShowDataRatIcon = b.getBoolean(
CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
+ config.show4gForLte = b.getBoolean(
+ CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
+ config.hideLtePlus = b.getBoolean(
+ CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
}
return config;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index a97effd..e20e267 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -956,11 +956,13 @@
changed |= onVolumeChangedW(stream, 0);
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+ if (isInitialStickyBroadcast()) mState.ringerModeExternal = rm;
if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
+ Util.ringerModeToString(rm));
changed = updateRingerModeExternalW(rm);
} else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+ if (isInitialStickyBroadcast()) mState.ringerModeInternal = rm;
if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
+ Util.ringerModeToString(rm));
changed = updateRingerModeInternalW(rm);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7abac00..798f8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -135,10 +135,6 @@
private final AccessibilityManagerWrapper mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
- private ColorStateList mActiveTint;
- private int mActiveAlpha;
- private ColorStateList mInactiveTint;
- private int mInactiveAlpha;
private boolean mShowing;
private boolean mShowA11yStream;
@@ -238,11 +234,6 @@
lp.gravity = ((FrameLayout.LayoutParams) mDialogView.getLayoutParams()).gravity;
mWindow.setAttributes(lp);
- mActiveTint = Utils.getColorAccent(mContext);
- mActiveAlpha = Color.alpha(mActiveTint.getDefaultColor());
- mInactiveTint = Utils.getColorAttr(mContext, android.R.attr.colorForeground);
- mInactiveAlpha = getAlphaAttr(android.R.attr.secondaryContentAlpha);
-
mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
mRinger = mDialog.findViewById(R.id.ringer);
if (mRinger != null) {
@@ -942,8 +933,12 @@
row.slider.requestFocus();
}
boolean useActiveColoring = isActive && row.slider.isEnabled();
- final ColorStateList tint = useActiveColoring ? mActiveTint : mInactiveTint;
- final int alpha = useActiveColoring ? mActiveAlpha : mInactiveAlpha;
+ final ColorStateList tint = useActiveColoring
+ ? Utils.getColorAccent(mContext)
+ : Utils.getColorAttr(mContext, android.R.attr.colorForeground);
+ final int alpha = useActiveColoring
+ ? Color.alpha(tint.getDefaultColor())
+ : getAlphaAttr(android.R.attr.secondaryContentAlpha);
if (tint == row.cachedTint) return;
row.slider.setProgressTintList(tint);
row.slider.setThumbTintList(tint);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 30d14e6..f85749a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -312,8 +312,8 @@
Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
+ mUrlBar.getWebDomain());
}
- final ViewState viewState = new ViewState(Session.this, urlBarId,
- Session.this, ViewState.STATE_URL_BAR);
+ final ViewState viewState = new ViewState(urlBarId, Session.this,
+ ViewState.STATE_URL_BAR);
mViewStates.put(urlBarId, viewState);
}
}
@@ -1813,8 +1813,6 @@
return sanitizers;
}
- // TODO: this method is called a few times in the save process, we should cache its results into
- // ViewState.
@Nullable
private AutofillValue getSanitizedValue(
@Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
@@ -1822,13 +1820,22 @@
@Nullable AutofillValue value) {
if (sanitizers == null || value == null) return value;
- final InternalSanitizer sanitizer = sanitizers.get(id);
- if (sanitizer == null) {
- return value;
- }
+ final ViewState state = mViewStates.get(id);
+ AutofillValue sanitized = state == null ? null : state.getSanitizedValue();
+ if (sanitized == null) {
+ final InternalSanitizer sanitizer = sanitizers.get(id);
+ if (sanitizer == null) {
+ return value;
+ }
- final AutofillValue sanitized = sanitizer.sanitize(value);
- if (sDebug) Slog.d(TAG, "Value for " + id + "(" + value + ") sanitized to " + sanitized);
+ sanitized = sanitizer.sanitize(value);
+ if (sDebug) {
+ Slog.d(TAG, "Value for " + id + "(" + value + ") sanitized to " + sanitized);
+ }
+ if (state != null) {
+ state.setSanitizedValue(sanitized);
+ }
+ }
return sanitized;
}
@@ -2149,7 +2156,7 @@
|| action == ACTION_VIEW_ENTERED) {
if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
boolean isIgnored = isIgnoredLocked(id);
- viewState = new ViewState(this, id, this,
+ viewState = new ViewState(id, this,
isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
@@ -2629,7 +2636,7 @@
if (viewState != null) {
viewState.setState(state);
} else {
- viewState = new ViewState(this, id, this, state);
+ viewState = new ViewState(id, this, state);
if (sVerbose) {
Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 49778f5..2cc6d20 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -77,7 +77,6 @@
public final AutofillId id;
private final Listener mListener;
- private final Session mSession;
private FillResponse mResponse;
private AutofillValue mCurrentValue;
@@ -87,8 +86,7 @@
private int mState;
private String mDatasetId;
- ViewState(Session session, AutofillId id, Listener listener, int state) {
- mSession = session;
+ ViewState(AutofillId id, Listener listener, int state) {
this.id = id;
mListener = listener;
mState = state;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 0b836f0..9cc550d 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -528,7 +528,7 @@
Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
public void run() {
mActivity.addErrorToDropBox(
- "watchdog", null, "system_server", null, null,
+ "watchdog", null, "system_server", null, null, null,
subject, null, stack, null);
}
};
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f4ec1f9..7235312 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3641,7 +3641,7 @@
}
if (anrMessage != null) {
- mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
+ proc.appNotResponding(null, null, null, null, false, anrMessage);
}
}
@@ -3666,7 +3666,7 @@
}
if (app != null) {
- mAm.mAppErrors.appNotResponding(app, null, null, false,
+ app.appNotResponding(null, null, null, null, false,
"Context.startForegroundService() did not then call Service.startForeground(): "
+ r);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2486787..c27ec6f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,9 +18,9 @@
import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+import static android.Manifest.permission.FILTER_EVENTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
@@ -28,9 +28,7 @@
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_NONE;
-import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
import static android.content.pm.PackageManager.GET_PROVIDERS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -101,9 +99,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
@@ -116,15 +111,12 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_NETWORK;
@@ -135,11 +127,16 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD;
import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_SHORT_CMD;
import static com.android.server.am.ActivityTaskManagerService.DUMP_CONTAINERS_CMD;
@@ -148,6 +145,10 @@
import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_CMD;
import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
import static com.android.server.am.ActivityTaskManagerService.DUMP_STARTER_CMD;
+import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.am.ActivityTaskManagerService.relaunchReasonToString;
+import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
import static com.android.server.am.MemoryStatUtil.hasMemcg;
import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
@@ -164,7 +165,6 @@
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerProto;
-import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -367,18 +367,15 @@
import libcore.util.EmptyArray;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
-import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -458,6 +455,12 @@
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
+ /**
+ * How long we wait for an provider to be published. Should be longer than
+ * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
+ */
+ static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
+
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// started with a wrapper for instrumentation (such as Valgrind) because it
@@ -501,6 +504,9 @@
*/
private static final long NETWORK_ACCESS_TIMEOUT_DEFAULT_MS = 200; // 0.2 sec
+ // The minimum memory growth threshold (in KB) for low RAM devices.
+ private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
+
/**
* State indicating that there is no need for any blocking for network.
*/
@@ -7374,6 +7380,7 @@
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
+ boolean providerRunning = false;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
@@ -7413,8 +7420,6 @@
}
}
- boolean providerRunning = false;
-
if (cpr != null && cpr.proc != null) {
providerRunning = !cpr.proc.killed;
@@ -7739,6 +7744,7 @@
}
// Wait for the provider to be published...
+ final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
@@ -7753,13 +7759,22 @@
return null;
}
try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp);
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
if (conn != null) {
conn.waiting = true;
}
- cpr.wait();
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name
+ + " providerRunning=" + providerRunning);
+ return null;
+ }
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
@@ -8119,8 +8134,8 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- mAppErrors.appNotResponding(host, null, null, false,
- "ContentProvider not responding");
+ host.appNotResponding(
+ null, null, null, null, false, "ContentProvider not responding");
}
});
}
@@ -9460,6 +9475,11 @@
// If at least 1/3 of our time since the last idle period has been spent
// with RAM low, then we want to kill processes.
boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
+ // If the processes' memory has increased by more than 1% of the total memory,
+ // or 10 MB, whichever is greater, then the processes' are eligible to be killed.
+ final long totalMemoryInKb = getTotalMemory() / 1000;
+ final long memoryGrowthThreshold =
+ Math.max(totalMemoryInKb / 100, MINIMUM_MEMORY_GROWTH_THRESHOLD);
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord proc = mLruProcesses.get(i);
@@ -9467,7 +9487,8 @@
if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
if (doKilling && proc.initialIdlePss != 0
- && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+ && proc.lastPss > ((proc.initialIdlePss * 3) / 2)
+ && proc.lastPss > (proc.initialIdlePss + memoryGrowthThreshold)) {
sb = new StringBuilder(128);
sb.append("Kill");
sb.append(proc.processName);
@@ -9781,16 +9802,17 @@
: StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
);
- final int relaunchReason = r == null ? ActivityRecord.RELAUNCH_REASON_NONE
+ final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
: r.getWindowProcessController().computeRelaunchReason();
- final String relaunchReasonString = ActivityRecord.relaunchReasonToString(relaunchReason);
+ final String relaunchReasonString = relaunchReasonToString(relaunchReason);
if (crashInfo.crashTag == null) {
crashInfo.crashTag = relaunchReasonString;
} else {
crashInfo.crashTag = crashInfo.crashTag + " " + relaunchReasonString;
}
- addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
+ addErrorToDropBox(
+ eventType, r, processName, null, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
}
@@ -9962,7 +9984,7 @@
StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
callingPid);
- addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);
+ addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo);
return r;
}
@@ -10061,17 +10083,18 @@
* Write a description of an error (crash, WTF, ANR) to the drop box.
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
* @param process which caused the error, null means the system server
- * @param activity which triggered the error, null if unknown
- * @param parent activity related to the error, null if unknown
+ * @param activityShortComponentName which triggered the error, null if unknown
+ * @param parentShortComponentName activity related to the error, null if unknown
+ * @param parentProcess parent process
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
* @param dataFile text file to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
*/
public void addErrorToDropBox(String eventType,
- ProcessRecord process, String processName, ActivityRecord activity,
- ActivityRecord parent, String subject,
- final String report, final File dataFile,
+ ProcessRecord process, String processName, String activityShortComponentName,
+ String parentShortComponentName, ProcessRecord parentProcess,
+ String subject, final String report, final File dataFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
@@ -10101,14 +10124,16 @@
.append(process.isInterestingToUserLocked() ? "Yes" : "No")
.append("\n");
}
- if (activity != null) {
- sb.append("Activity: ").append(activity.shortComponentName).append("\n");
+ if (activityShortComponentName != null) {
+ sb.append("Activity: ").append(activityShortComponentName).append("\n");
}
- if (parent != null && parent.app != null && parent.app.getPid() != process.pid) {
- sb.append("Parent-Process: ").append(parent.app.mName).append("\n");
- }
- if (parent != null && parent != activity) {
- sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
+ if (parentShortComponentName != null) {
+ if (parentProcess != null && parentProcess.pid != process.pid) {
+ sb.append("Parent-Process: ").append(parentProcess.processName).append("\n");
+ }
+ if (!parentShortComponentName.equals(activityShortComponentName)) {
+ sb.append("Parent-Activity: ").append(parentShortComponentName).append("\n");
+ }
}
if (subject != null) {
sb.append("Subject: ").append(subject).append("\n");
@@ -13983,7 +14008,7 @@
dropBuilder.append(catSw.toString());
StatsLog.write(StatsLog.LOW_MEM_REPORTED);
addErrorToDropBox("lowmem", null, "system_server", null,
- null, tag.toString(), dropBuilder.toString(), null, null);
+ null, null, tag.toString(), dropBuilder.toString(), null, null);
//Slog.i(TAG, "Sent to dropbox:");
//Slog.i(TAG, dropBuilder.toString());
synchronized (ActivityManagerService.this) {
@@ -20295,6 +20320,83 @@
: UsageEvents.Event.KEYGUARD_HIDDEN);
}
}
+
+ @Override
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
+ synchronized (ActivityManagerService.this) {
+ return ActivityManagerService.this.inputDispatchingTimedOut(
+ pid, aboveSystem, reason);
+ }
+ }
+
+ @Override
+ public boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
+ boolean aboveSystem, String reason) {
+ return ActivityManagerService.this.inputDispatchingTimedOut((ProcessRecord) proc,
+ activityShortComponentName, aInfo, parentShortComponentName,
+ (WindowProcessController) parentProc, aboveSystem, reason);
+
+ }
+ }
+
+ long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+ ProcessRecord proc;
+ long timeout;
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ }
+
+ if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
+ return -1;
+ }
+
+ return timeout;
+ }
+
+ /**
+ * Handle input dispatching timeouts.
+ * @return whether input dispatching should be aborted or not.
+ */
+ boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName,
+ WindowProcessController parentProcess, boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+
+ final String annotation;
+ if (reason == null) {
+ annotation = "Input dispatching timed out";
+ } else {
+ annotation = "Input dispatching timed out (" + reason + ")";
+ }
+
+ if (proc != null) {
+ synchronized (this) {
+ if (proc.isDebugging()) {
+ return false;
+ }
+
+ if (proc.getActiveInstrumentation() != null) {
+ Bundle info = new Bundle();
+ info.putString("shortMsg", "keyDispatchingTimedOut");
+ info.putString("longMsg", annotation);
+ finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
+ return true;
+ }
+ }
+ proc.appNotResponding(activityShortComponentName, aInfo,
+ parentShortComponentName, parentProcess, aboveSystem, annotation);
+ }
+
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d837118..865c774 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -81,6 +81,7 @@
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -114,6 +115,9 @@
import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG;
import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG;
import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.am.TaskPersister.DEBUG;
@@ -338,12 +342,6 @@
int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
- // This activity is not being relaunched, or being relaunched for a non-resize reason.
- static final int RELAUNCH_REASON_NONE = 0;
- // This activity is being relaunched due to windowing mode change.
- static final int RELAUNCH_REASON_WINDOWING_MODE_RESIZE = 1;
- // This activity is being relaunched due to a free-resize operation.
- static final int RELAUNCH_REASON_FREE_RESIZE = 2;
// Marking the reason why this activity is being relaunched. Mainly used to track that this
// activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in
// pre-NYC apps that don't have a sense of being resized.
@@ -2114,12 +2112,16 @@
windowFromSameProcessAsActivity =
!hasProcess() || app.getPid() == windowPid || windowPid == -1;
}
+
if (windowFromSameProcessAsActivity) {
- return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
+ return service.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
+ anrActivity.shortComponentName, anrActivity.appInfo, shortComponentName,
+ app, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
- return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
+ return service.mAmInternal.inputDispatchingTimedOut(
+ windowPid, false /* aboveSystem */, reason) < 0;
}
}
@@ -2211,12 +2213,13 @@
}
/**
- * @return display id to which this record is attached, -1 if not attached.
+ * @return display id to which this record is attached,
+ * {@link android.view.Display#INVALID_DISPLAY} if not attached.
*/
int getDisplayId() {
final ActivityStack stack = getStack();
if (stack == null) {
- return -1;
+ return INVALID_DISPLAY;
}
return stack.mDisplayId;
}
@@ -2281,6 +2284,11 @@
// We don't show starting window for overlay activities.
return;
}
+ if (pendingOptions != null
+ && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ // Don't show starting window when using shared element transition.
+ return;
+ }
final CompatibilityInfo compatInfo =
service.compatibilityInfoForPackageLocked(info.applicationInfo);
@@ -3006,17 +3014,6 @@
mWindowContainerController.registerRemoteAnimations(definition);
}
- static String relaunchReasonToString(int relaunchReason) {
- switch (relaunchReason) {
- case RELAUNCH_REASON_WINDOWING_MODE_RESIZE:
- return "window_resize";
- case RELAUNCH_REASON_FREE_RESIZE:
- return "free_resize";
- default:
- return null;
- }
- }
-
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 695ffe2..12ed726 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -81,8 +81,8 @@
import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_FREE_RESIZE;
-import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.ActivityState.FINISHING;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c455704..12c6dec 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -75,7 +75,7 @@
import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
import static com.android.server.am.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_NONE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
@@ -2258,9 +2258,9 @@
* Finish the topmost activities in all stacks that belong to the crashed app.
* @param app The app that crashed.
* @param reason Reason to perform this action.
- * @return The task that was finished in this stack, {@code null} if haven't found any.
+ * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
- TaskRecord finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
+ int finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
TaskRecord finishedTask = null;
ActivityStack focusedStack = getTopDisplayFocusedStack();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2275,7 +2275,7 @@
}
}
}
- return finishedTask;
+ return finishedTask != null ? finishedTask.taskId : INVALID_TASK_ID;
}
void finishVoiceTask(IVoiceInteractionSession session) {
@@ -2466,7 +2466,7 @@
}
if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
if (r != null) {
- stack = (T) getValidLaunchStackOnDisplay(displayId, r, options);
+ stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options);
if (stack != null) {
return stack;
}
@@ -2531,10 +2531,11 @@
* If there is no such stack, new dynamic stack can be created.
* @param displayId Target display.
* @param r Activity that should be launched there.
+ * @param candidateTask The possible task the activity might be put in.
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
- @Nullable ActivityOptions options) {
+ @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options) {
final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId);
if (activityDisplay == null) {
throw new IllegalArgumentException(
@@ -2545,6 +2546,13 @@
return null;
}
+ // If {@code r} is already in target display and its task is the same as the candidate task,
+ // the intention should be getting a launch stack for the reusable activity, so we can use
+ // the existing stack.
+ if (r.getDisplayId() == displayId && r.getTask() == candidateTask) {
+ return candidateTask.getStack();
+ }
+
// Return the topmost valid stack on the display.
for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
final ActivityStack stack = activityDisplay.getChildAt(i);
@@ -2565,6 +2573,11 @@
return null;
}
+ ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
+ @Nullable ActivityOptions options) {
+ return getValidLaunchStackOnDisplay(displayId, r, null /* candidateTask */, options);
+ }
+
// TODO: Can probably be consolidated into getLaunchStack()...
private boolean isValidLaunchStack(ActivityStack stack, int displayId, ActivityRecord r) {
switch (stack.getActivityType()) {
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index b7bbfe8..2d27017 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -277,7 +277,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.function.Predicate;
/**
* System service for managing activities and their containers (task, stacks, displays,... ).
@@ -295,9 +294,9 @@
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
// How long we wait until we timeout on key dispatching.
- private static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
+ public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
// How long we wait until we timeout on key dispatching during instrumentation.
- private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
/** Used to indicate that an app transition should be animated. */
static final boolean ANIMATE = true;
@@ -314,7 +313,15 @@
public static final String DUMP_RECENTS_CMD = "recents" ;
public static final String DUMP_RECENTS_SHORT_CMD = "r" ;
+ /** This activity is not being relaunched, or being relaunched for a non-resize reason. */
+ public static final int RELAUNCH_REASON_NONE = 0;
+ /** This activity is being relaunched due to windowing mode change. */
+ public static final int RELAUNCH_REASON_WINDOWING_MODE_RESIZE = 1;
+ /** This activity is being relaunched due to a free-resize operation. */
+ public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
+
Context mContext;
+
/**
* This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
* change at runtime. Use mContext for non-UI purposes.
@@ -1362,7 +1369,7 @@
Slog.i(TAG, "Removing task failed to finish activity");
}
// Explicitly dismissing the activity so reset its relaunch flag.
- r.mRelaunchReason = ActivityRecord.RELAUNCH_REASON_NONE;
+ r.mRelaunchReason = RELAUNCH_REASON_NONE;
} else {
res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
@@ -4325,6 +4332,17 @@
}
}
+ public static String relaunchReasonToString(int relaunchReason) {
+ switch (relaunchReason) {
+ case RELAUNCH_REASON_WINDOWING_MODE_RESIZE:
+ return "window_resize";
+ case RELAUNCH_REASON_FREE_RESIZE:
+ return "free_resize";
+ default:
+ return null;
+ }
+ }
+
ActivityStack getTopDisplayFocusedStack() {
return mStackSupervisor.getTopDisplayFocusedStack();
}
@@ -4932,70 +4950,7 @@
}
private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
- if (r != null && (r.isInstrumenting() || r.isUsingWrapper())) {
- return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
- }
- return KEY_DISPATCHING_TIMEOUT_MS;
- }
-
- long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
- if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission " + FILTER_EVENTS);
- }
- WindowProcessController proc;
- long timeout;
- synchronized (mGlobalLock) {
- proc = mPidMap.get(pid);
- timeout = getInputDispatchingTimeoutLocked(proc);
- }
-
- if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
- return -1;
- }
-
- return timeout;
- }
-
- /**
- * Handle input dispatching timeouts.
- * Returns whether input dispatching should be aborted or not.
- */
- boolean inputDispatchingTimedOut(final WindowProcessController proc,
- final ActivityRecord activity, final ActivityRecord parent,
- final boolean aboveSystem, String reason) {
- if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission " + FILTER_EVENTS);
- }
-
- final String annotation;
- if (reason == null) {
- annotation = "Input dispatching timed out";
- } else {
- annotation = "Input dispatching timed out (" + reason + ")";
- }
-
- if (proc != null) {
- synchronized (mGlobalLock) {
- if (proc.isDebugging()) {
- return false;
- }
-
- if (proc.isInstrumenting()) {
- Bundle info = new Bundle();
- info.putString("shortMsg", "keyDispatchingTimedOut");
- info.putString("longMsg", annotation);
- mAm.finishInstrumentationLocked(
- (ProcessRecord) proc.mOwner, Activity.RESULT_CANCELED, info);
- return true;
- }
- }
- mH.post(() -> {
- mAm.mAppErrors.appNotResponding(
- (ProcessRecord) proc.mOwner, activity, parent, aboveSystem, annotation);
- });
- }
-
- return true;
+ return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
}
/**
@@ -6031,14 +5986,6 @@
}
@Override
- public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
- synchronized (mGlobalLock) {
- return ActivityTaskManagerService.this.inputDispatchingTimedOut(
- pid, aboveSystem, reason);
- }
- }
-
- @Override
public void onProcessMapped(int pid, WindowProcessController proc) {
synchronized (mGlobalLock) {
mPidMap.put(pid, proc);
@@ -6619,19 +6566,18 @@
if (mHomeProcess != null && (dumpPackage == null
|| mHomeProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mHomeProcess.mOwner).writeToProto(proto, HOME_PROC);
+ mHomeProcess.writeToProto(proto, HOME_PROC);
}
if (mPreviousProcess != null && (dumpPackage == null
|| mPreviousProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mPreviousProcess.mOwner).writeToProto(proto, PREVIOUS_PROC);
+ mPreviousProcess.writeToProto(proto, PREVIOUS_PROC);
proto.write(PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
}
if (mHeavyWeightProcess != null && (dumpPackage == null
|| mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mHeavyWeightProcess.mOwner).writeToProto(
- proto, HEAVY_WEIGHT_PROC);
+ mHeavyWeightProcess.writeToProto(proto, HEAVY_WEIGHT_PROC);
}
for (Map.Entry<String, Integer> entry
@@ -6714,5 +6660,12 @@
mStackSupervisor.handleAppCrashLocked(wpc);
}
}
+
+ @Override
+ public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) {
+ synchronized (mGlobalLock) {
+ return mStackSupervisor.finishTopCrashedActivitiesLocked(crashedApp, reason);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index cde633d..a80a5b5 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -63,7 +65,7 @@
mService = service;
mProc = data.proc;
mResult = data.result;
- mIsRestartable = (data.task != null || data.isRestartableForService)
+ mIsRestartable = (data.taskId != INVALID_TASK_ID || data.isRestartableForService)
&& Settings.Global.getInt(context.getContentResolver(),
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, 0) != 0;
BidiFormatter bidi = BidiFormatter.getInstance();
@@ -209,7 +211,7 @@
static class Data {
AppErrorResult result;
- TaskRecord task;
+ int taskId;
boolean repeating;
ProcessRecord proc;
boolean isRestartableForService;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index be1f9ea..83c4ab5 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -16,12 +16,13 @@
package com.android.server.am;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.SYSTEM_DEBUGGABLE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -46,21 +47,17 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.os.ProcessCpuTracker;
import com.android.server.RescueParty;
import com.android.server.Watchdog;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
@@ -411,11 +408,10 @@
}
final int relaunchReason = r != null
- ? r.getWindowProcessController().computeRelaunchReason()
- : ActivityRecord.RELAUNCH_REASON_NONE;
+ ? r.getWindowProcessController().computeRelaunchReason() : RELAUNCH_REASON_NONE;
AppErrorResult result = new AppErrorResult();
- TaskRecord task;
+ int taskId;
synchronized (mService) {
/**
* If crash is handled by instance of {@link android.app.IActivityController},
@@ -428,7 +424,7 @@
// Suppress crash dialog if the process is being relaunched due to a crash during a free
// resize.
- if (relaunchReason == ActivityRecord.RELAUNCH_REASON_FREE_RESIZE) {
+ if (relaunchReason == RELAUNCH_REASON_FREE_RESIZE) {
return;
}
@@ -458,7 +454,7 @@
final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
- task = data.task;
+ taskId = data.taskId;
msg.obj = data;
mService.mUiHandler.sendMessage(msg);
}
@@ -476,24 +472,14 @@
}
if (res == AppErrorDialog.RESTART) {
mService.removeProcessLocked(r, false, true, "crash");
- if (task != null) {
+ if (taskId != INVALID_TASK_ID) {
try {
- mService.mActivityTaskManager.startActivityFromRecents(task.taskId,
+ mService.mActivityTaskManager.startActivityFromRecents(taskId,
ActivityOptions.makeBasic().toBundle());
} catch (IllegalArgumentException e) {
- // Hmm, that didn't work, app might have crashed before creating a
- // recents entry. Let's see if we have a safe-to-restart intent.
- final Set<String> cats = task.intent != null
- ? task.intent.getCategories() : null;
- if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
- mService.mActivityTaskManager.getActivityStartController().startActivityInPackage(
- task.mCallingUid, callingPid, callingUid, task.mCallingPackage,
- task.intent, null, null, null, 0, 0,
- new SafeActivityOptions(ActivityOptions.makeBasic()),
- task.userId, null,
- "AppErrors", false /*validateIncomingUser*/,
- null /* originatingPendingIntent */);
- }
+ // Hmm...that didn't work. Task should either be in recents or associated
+ // with a stack.
+ Slog.e(TAG, "Could not restart taskId=" + taskId, e);
}
}
}
@@ -582,27 +568,12 @@
app.setCrashing(true);
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
- startAppProblemLocked(app);
+ app.startAppProblemLocked();
app.getWindowProcessController().stopFreezingActivities();
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
- void startAppProblemLocked(ProcessRecord app) {
- // If this app is not running under the current user, then we
- // can't give it a report button because that would require
- // launching the report UI under a different user.
- app.errorReportReceiver = null;
-
- for (int userId : mService.mUserController.getCurrentProfileIds()) {
- if (app.userId == userId) {
- app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
- mContext, app.info.packageName, app.info.flags);
- }
- }
- mService.skipCurrentReceiverLocked(app);
- }
-
/**
* Generate a process error record, suitable for attachment to a ProcessRecord.
*
@@ -616,7 +587,7 @@
*
* @return Returns a fully-formed ProcessErrorStateInfo record.
*/
- private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
+ ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
@@ -751,11 +722,10 @@
}
mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
} else {
- final TaskRecord affectedTask =
- mService.mActivityTaskManager.mStackSupervisor.finishTopCrashedActivitiesLocked(
+ final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
app.getWindowProcessController(), reason);
if (data != null) {
- data.task = affectedTask;
+ data.taskId = affectedTaskId;
}
if (data != null && crashTimePersistent != null
&& now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
@@ -855,259 +825,13 @@
}
}
- void stopReportingCrashesLocked(ProcessRecord proc) {
+ private void stopReportingCrashesLocked(ProcessRecord proc) {
if (mAppsNotReportingCrashes == null) {
mAppsNotReportingCrashes = new ArraySet<>();
}
mAppsNotReportingCrashes.add(proc.info.packageName);
}
- static boolean isInterestingForBackgroundTraces(ProcessRecord app) {
- // The system_server is always considered interesting.
- if (app.pid == MY_PID) {
- return true;
- }
-
- // A package is considered interesting if any of the following is true :
- //
- // - It's displaying an activity.
- // - It's the SystemUI.
- // - It has an overlay or a top UI visible.
- //
- // NOTE: The check whether a given ProcessRecord belongs to the systemui
- // process is a bit of a kludge, but the same pattern seems repeated at
- // several places in the system server.
- return app.isInterestingToUserLocked() ||
- (app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
- (app.hasTopUi() || app.hasOverlayUi());
- }
-
- final void appNotResponding(ProcessRecord app, ActivityRecord activity,
- ActivityRecord parent, boolean aboveSystem, final String annotation) {
- ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
- SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
-
- if (mService.mActivityTaskManager.mController != null) {
- try {
- // 0 == continue, -1 = kill process immediately
- int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
- app.processName, app.pid, annotation);
- if (res < 0 && app.pid != MY_PID) {
- app.kill("anr", true);
- }
- } catch (RemoteException e) {
- mService.mActivityTaskManager.mController = null;
- Watchdog.getInstance().setActivityController(null);
- }
- }
-
- long anrTime = SystemClock.uptimeMillis();
- if (ActivityManagerService.MONITOR_CPU_USAGE) {
- mService.updateCpuStatsNow();
- }
-
- // Unless configured otherwise, swallow ANRs in background processes & kill the process.
- boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-
- boolean isSilentANR;
-
- synchronized (mService) {
- // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
- if (mService.mActivityTaskManager.mShuttingDown) {
- Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.isNotResponding()) {
- Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
- return;
- } else if (app.isCrashing()) {
- Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.killedByAm) {
- Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.killed) {
- Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);
- return;
- }
-
- // In case we come through here for the same app before completing
- // this one, mark as anring now so we will bail out.
- app.setNotResponding(true);
-
- // Log the ANR to the event log.
- EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
- app.processName, app.info.flags, annotation);
-
- // Dump thread traces as quickly as we can, starting with "interesting" processes.
- firstPids.add(app.pid);
-
- // Don't dump other PIDs if it's a background ANR
- isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
- if (!isSilentANR) {
- int parentPid = app.pid;
- if (parent != null && parent.app != null && parent.app.getPid() > 0) {
- parentPid = parent.app.getPid();
- }
- if (parentPid != app.pid) firstPids.add(parentPid);
-
- if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
-
- for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord r = mService.mLruProcesses.get(i);
- if (r != null && r.thread != null) {
- int pid = r.pid;
- if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
- if (r.isPersistent()) {
- firstPids.add(pid);
- if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
- } else if (r.treatLikeActivity) {
- firstPids.add(pid);
- if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
- } else {
- lastPids.put(pid, Boolean.TRUE);
- if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
- }
- }
- }
- }
- }
- }
-
- // Log the ANR to the main log.
- StringBuilder info = new StringBuilder();
- info.setLength(0);
- info.append("ANR in ").append(app.processName);
- if (activity != null && activity.shortComponentName != null) {
- info.append(" (").append(activity.shortComponentName).append(")");
- }
- info.append("\n");
- info.append("PID: ").append(app.pid).append("\n");
- if (annotation != null) {
- info.append("Reason: ").append(annotation).append("\n");
- }
- if (parent != null && parent != activity) {
- info.append("Parent: ").append(parent.shortComponentName).append("\n");
- }
-
- ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
-
- // don't dump native PIDs for background ANRs unless it is the process of interest
- String[] nativeProcs = null;
- if (isSilentANR) {
- for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
- if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {
- nativeProcs = new String[] { app.processName };
- break;
- }
- }
- } else {
- nativeProcs = NATIVE_STACKS_OF_INTEREST;
- }
-
- int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
- ArrayList<Integer> nativePids = null;
-
- if (pids != null) {
- nativePids = new ArrayList<Integer>(pids.length);
- for (int i : pids) {
- nativePids.add(i);
- }
- }
-
- // For background ANRs, don't pass the ProcessCpuTracker to
- // avoid spending 1/2 second collecting stats to rank lastPids.
- File tracesFile = ActivityManagerService.dumpStackTraces(
- firstPids,
- (isSilentANR) ? null : processCpuTracker,
- (isSilentANR) ? null : lastPids,
- nativePids);
-
- String cpuInfo = null;
- if (ActivityManagerService.MONITOR_CPU_USAGE) {
- mService.updateCpuStatsNow();
- synchronized (mService.mProcessCpuTracker) {
- cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
- }
- info.append(processCpuTracker.printCurrentLoad());
- info.append(cpuInfo);
- }
-
- info.append(processCpuTracker.printCurrentState(anrTime));
-
- Slog.e(TAG, info.toString());
- if (tracesFile == null) {
- // There is no trace file, so dump (only) the alleged culprit's threads to the log
- Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
- }
-
- StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,
- activity == null ? "unknown": activity.shortComponentName, annotation,
- (app.info != null) ? (app.info.isInstantApp()
- ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
- : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
- : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
- app != null ? (app.isInterestingToUserLocked()
- ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
- : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND)
- : StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN);
- mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
- cpuInfo, tracesFile, null);
-
- if (mService.mActivityTaskManager.mController != null) {
- try {
- // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
- int res = mService.mActivityTaskManager.mController.appNotResponding(
- app.processName, app.pid, info.toString());
- if (res != 0) {
- if (res < 0 && app.pid != MY_PID) {
- app.kill("anr", true);
- } else {
- synchronized (mService) {
- mService.mServices.scheduleServiceTimeoutLocked(app);
- }
- }
- return;
- }
- } catch (RemoteException e) {
- mService.mActivityTaskManager.mController = null;
- Watchdog.getInstance().setActivityController(null);
- }
- }
-
- synchronized (mService) {
- mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
-
- if (isSilentANR) {
- app.kill("bg anr", true);
- return;
- }
-
- // Set the app's notResponding state, and look up the errorReportReceiver
- makeAppNotRespondingLocked(app,
- activity != null ? activity.shortComponentName : null,
- annotation != null ? "ANR " + annotation : "ANR",
- info.toString());
-
- // Bring up the infamous App Not Responding dialog
- Message msg = Message.obtain();
- msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
- msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
-
- mService.mUiHandler.sendMessage(msg);
- }
- }
-
- private void makeAppNotRespondingLocked(ProcessRecord app,
- String activity, String shortMsg, String longMsg) {
- app.setNotResponding(true);
- app.notRespondingReport = generateProcessError(app,
- ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
- activity, shortMsg, longMsg, null);
- startAppProblemLocked(app);
- app.getWindowProcessController().stopFreezingActivities();
- }
-
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 7c983ff..cb76e2f 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.content.pm.ApplicationInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -58,8 +59,8 @@
setCancelable(false);
int resid;
- CharSequence name1 = data.activity != null
- ? data.activity.info.loadLabel(context.getPackageManager())
+ CharSequence name1 = data.aInfo != null
+ ? data.aInfo.loadLabel(context.getPackageManager())
: null;
CharSequence name2 = null;
if ((mProc.pkgList.size() == 1) &&
@@ -181,12 +182,12 @@
static class Data {
final ProcessRecord proc;
- final ActivityRecord activity;
+ final ApplicationInfo aInfo;
final boolean aboveSystem;
- Data(ProcessRecord proc, ActivityRecord activity, boolean aboveSystem) {
+ Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem) {
this.proc = proc;
- this.activity = activity;
+ this.aInfo = aInfo;
this.aboveSystem = aboveSystem;
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index e2035f6..a13cf4d 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -191,7 +191,7 @@
@Override
public void run() {
- mService.mAppErrors.appNotResponding(mApp, null, null, false, mAnnotation);
+ mApp.appNotResponding(null, null, null, null, false, mAnnotation);
}
}
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 23ae77d..85ee7e6 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -46,6 +46,27 @@
static final String[] MEMORY_STAT_INTERESTING_NATIVE_PROCESSES = new String[]{
"/system/bin/statsd", // Stats daemon.
"/system/bin/surfaceflinger",
+ "/system/bin/apexd", // APEX daemon.
+ "/system/bin/audioserver",
+ "/system/bin/cameraserver",
+ "/system/bin/drmserver",
+ "/system/bin/healthd",
+ "/system/bin/incidentd",
+ "/system/bin/installd",
+ "/system/bin/lmkd", // Low memory killer daemon.
+ "/system/bin/logd",
+ "media.codec",
+ "media.extractor",
+ "media.metrics",
+ "/system/bin/mediadrmserver",
+ "/system/bin/mediaserver",
+ "/system/bin/performanced",
+ "/system/bin/tombstoned",
+ "/system/bin/traced", // Perfetto.
+ "/system/bin/traced_probes", // Perfetto.
+ "webview_zygote",
+ "zygote",
+ "zygote64",
};
static final int BYTES_IN_KILOBYTE = 1024;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index b9c6fa6..2dcddff 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -288,12 +288,19 @@
resolvedType = key.requestResolvedType;
}
+ // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
+ // can specify a consistent launch mode even if the PendingIntent is immutable
+ final ActivityOptions opts = ActivityOptions.fromBundle(options);
+ if (opts != null) {
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ }
+
// Extract options before clearing calling identity
mergedOptions = key.options;
if (mergedOptions == null) {
- mergedOptions = SafeActivityOptions.fromBundle(options);
+ mergedOptions = new SafeActivityOptions(opts);
} else {
- mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
+ mergedOptions.setCallerOptions(opts);
}
if (whitelistDuration != null) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 145791c..0eb535b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -18,10 +18,14 @@
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.MY_PID;
import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IApplicationThread;
import android.content.ComponentName;
@@ -32,16 +36,19 @@
import android.os.Binder;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -49,7 +56,10 @@
import com.android.internal.app.procstats.ProcessState;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.server.Watchdog;
+import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -735,6 +745,7 @@
}
}
+ @Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(ProcessRecordProto.PID, pid);
@@ -1168,4 +1179,267 @@
public long getCpuTime() {
return mService.mProcessCpuTracker.getCpuTimeForPid(pid);
}
+
+ public long getInputDispatchingTimeout() {
+ return mWindowProcessController.getInputDispatchingTimeout();
+ }
+
+ void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
+ String parentShortComponentName, WindowProcessController parentProcess,
+ boolean aboveSystem, String annotation) {
+ ArrayList<Integer> firstPids = new ArrayList<>(5);
+ SparseArray<Boolean> lastPids = new SparseArray<>(20);
+
+ if (mService.mActivityTaskManager.mController != null) {
+ try {
+ // 0 == continue, -1 = kill process immediately
+ int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
+ processName, pid, annotation);
+ if (res < 0 && pid != MY_PID) {
+ kill("anr", true);
+ }
+ } catch (RemoteException e) {
+ mService.mActivityTaskManager.mController = null;
+ Watchdog.getInstance().setActivityController(null);
+ }
+ }
+
+ long anrTime = SystemClock.uptimeMillis();
+ if (ActivityManagerService.MONITOR_CPU_USAGE) {
+ mService.updateCpuStatsNow();
+ }
+
+ // Unless configured otherwise, swallow ANRs in background processes & kill the process.
+ boolean showBackground = Settings.Secure.getInt(mService.mContext.getContentResolver(),
+ Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+
+ boolean isSilentANR;
+
+ synchronized (mService) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mService.mActivityTaskManager.mShuttingDown) {
+ Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (isNotResponding()) {
+ Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
+ return;
+ } else if (isCrashing()) {
+ Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (killedByAm) {
+ Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (killed) {
+ Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
+ return;
+ }
+
+ // In case we come through here for the same app before completing
+ // this one, mark as anring now so we will bail out.
+ setNotResponding(true);
+
+ // Log the ANR to the event log.
+ EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
+ annotation);
+
+ // Dump thread traces as quickly as we can, starting with "interesting" processes.
+ firstPids.add(pid);
+
+ // Don't dump other PIDs if it's a background ANR
+ isSilentANR = !showBackground && !isInterestingForBackgroundTraces();
+ if (!isSilentANR) {
+ int parentPid = pid;
+ if (parentProcess != null && parentProcess.getPid() > 0) {
+ parentPid = parentProcess.getPid();
+ }
+ if (parentPid != pid) firstPids.add(parentPid);
+
+ if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID);
+
+ for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mService.mLruProcesses.get(i);
+ if (r != null && r.thread != null) {
+ int myPid = r.pid;
+ if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) {
+ if (r.isPersistent()) {
+ firstPids.add(myPid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
+ } else if (r.treatLikeActivity) {
+ firstPids.add(myPid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
+ } else {
+ lastPids.put(myPid, Boolean.TRUE);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Log the ANR to the main log.
+ StringBuilder info = new StringBuilder();
+ info.setLength(0);
+ info.append("ANR in ").append(processName);
+ if (activityShortComponentName != null) {
+ info.append(" (").append(activityShortComponentName).append(")");
+ }
+ info.append("\n");
+ info.append("PID: ").append(pid).append("\n");
+ if (annotation != null) {
+ info.append("Reason: ").append(annotation).append("\n");
+ }
+ if (parentShortComponentName != null
+ && parentShortComponentName.equals(activityShortComponentName)) {
+ info.append("Parent: ").append(parentShortComponentName).append("\n");
+ }
+
+ ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
+
+ // don't dump native PIDs for background ANRs unless it is the process of interest
+ String[] nativeProcs = null;
+ if (isSilentANR) {
+ for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
+ if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) {
+ nativeProcs = new String[] { processName };
+ break;
+ }
+ }
+ } else {
+ nativeProcs = NATIVE_STACKS_OF_INTEREST;
+ }
+
+ int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
+ ArrayList<Integer> nativePids = null;
+
+ if (pids != null) {
+ nativePids = new ArrayList<>(pids.length);
+ for (int i : pids) {
+ nativePids.add(i);
+ }
+ }
+
+ // For background ANRs, don't pass the ProcessCpuTracker to
+ // avoid spending 1/2 second collecting stats to rank lastPids.
+ File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
+ (isSilentANR) ? null : processCpuTracker, (isSilentANR) ? null : lastPids,
+ nativePids);
+
+ String cpuInfo = null;
+ if (ActivityManagerService.MONITOR_CPU_USAGE) {
+ mService.updateCpuStatsNow();
+ synchronized (mService.mProcessCpuTracker) {
+ cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
+ }
+ info.append(processCpuTracker.printCurrentLoad());
+ info.append(cpuInfo);
+ }
+
+ info.append(processCpuTracker.printCurrentState(anrTime));
+
+ Slog.e(TAG, info.toString());
+ if (tracesFile == null) {
+ // There is no trace file, so dump (only) the alleged culprit's threads to the log
+ Process.sendSignal(pid, Process.SIGNAL_QUIT);
+ }
+
+ StatsLog.write(StatsLog.ANR_OCCURRED, uid, processName,
+ activityShortComponentName == null ? "unknown": activityShortComponentName,
+ annotation,
+ (this.info != null) ? (this.info.isInstantApp()
+ ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+ isInterestingToUserLocked()
+ ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
+ : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND);
+ final ProcessRecord parentPr = parentProcess != null
+ ? (ProcessRecord) parentProcess.mOwner : null;
+ mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
+ parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
+
+ if (mService.mActivityTaskManager.mController != null) {
+ try {
+ // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
+ int res = mService.mActivityTaskManager.mController.appNotResponding(
+ processName, pid, info.toString());
+ if (res != 0) {
+ if (res < 0 && pid != MY_PID) {
+ kill("anr", true);
+ } else {
+ synchronized (mService) {
+ mService.mServices.scheduleServiceTimeoutLocked(this);
+ }
+ }
+ return;
+ }
+ } catch (RemoteException e) {
+ mService.mActivityTaskManager.mController = null;
+ Watchdog.getInstance().setActivityController(null);
+ }
+ }
+
+ synchronized (mService) {
+ mService.mBatteryStatsService.noteProcessAnr(processName, uid);
+
+ if (isSilentANR) {
+ kill("bg anr", true);
+ return;
+ }
+
+ // Set the app's notResponding state, and look up the errorReportReceiver
+ makeAppNotRespondingLocked(activityShortComponentName,
+ annotation != null ? "ANR " + annotation : "ANR", info.toString());
+
+ // Bring up the infamous App Not Responding dialog
+ Message msg = Message.obtain();
+ msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
+ msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);
+
+ mService.mUiHandler.sendMessage(msg);
+ }
+ }
+
+ private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) {
+ setNotResponding(true);
+ notRespondingReport = mService.mAppErrors.generateProcessError(this,
+ ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
+ activity, shortMsg, longMsg, null);
+ startAppProblemLocked();
+ getWindowProcessController().stopFreezingActivities();
+ }
+
+ void startAppProblemLocked() {
+ // If this app is not running under the current user, then we can't give it a report button
+ // because that would require launching the report UI under a different user.
+ errorReportReceiver = null;
+
+ for (int userId : mService.mUserController.getCurrentProfileIds()) {
+ if (this.userId == userId) {
+ errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mService.mContext, info.packageName, info.flags);
+ }
+ }
+ mService.skipCurrentReceiverLocked(this);
+ }
+
+ private boolean isInterestingForBackgroundTraces() {
+ // The system_server is always considered interesting.
+ if (pid == MY_PID) {
+ return true;
+ }
+
+ // A package is considered interesting if any of the following is true :
+ //
+ // - It's displaying an activity.
+ // - It's the SystemUI.
+ // - It has an overlay or a top UI visible.
+ //
+ // NOTE: The check whether a given ProcessRecord belongs to the systemui
+ // process is a bit of a kludge, but the same pattern seems repeated at
+ // several places in the system server.
+ return isInterestingToUserLocked() ||
+ (info != null && "com.android.systemui".equals(info.packageName))
+ || (hasTopUi() || hasOverlayUi());
+ }
}
diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index eae28127..111adec 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -114,6 +114,26 @@
private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options,
LaunchParams currentParams, LaunchParams outParams) {
+ final ActivityRecord root;
+ if (task != null) {
+ root = task.getRootActivity() == null ? activity : task.getRootActivity();
+ } else {
+ root = activity;
+ }
+
+ // TODO: Investigate whether we can safely ignore all cases where we don't have root
+ // activity available. Note we can't know if the bounds are valid if we're not sure of the
+ // requested orientation of the root activity. Therefore if we found such a case we may need
+ // to pass the activity into this modifier in that case.
+ if (root == null) {
+ // There is a case that can lead us here. The caller is moving the top activity that is
+ // in a task that has multiple activities to PIP mode. For that the caller is creating a
+ // new task to host the activity so that we only move the top activity to PIP mode and
+ // keep other activities in the previous task. There is no point to apply the launch
+ // logic in this case.
+ return RESULT_SKIP;
+ }
+
// STEP 1: Determine the display to launch the activity/task.
final int displayId = getPreferredLaunchDisplay(options, source, currentParams);
outParams.mPreferredDisplayId = displayId;
@@ -123,12 +143,6 @@
+ display.getWindowingMode());
}
- final ActivityRecord root;
- if (task != null) {
- root = (task.getRootActivity() == null ? activity : task.getRootActivity());
- } else {
- root = activity;
- }
// STEP 2: Resolve launch windowing mode.
// STEP 2.1: Determine if any parameter has specified initial bounds. That might be the
// launch bounds from activity options, or size/gravity passed in layout. It also treats the
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index 7e3893b..792b66b 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -30,6 +30,9 @@
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import android.app.Activity;
import android.app.ActivityThread;
@@ -44,6 +47,7 @@
import android.util.Log;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.wm.ConfigurationContainer;
@@ -614,12 +618,19 @@
final int activitiesSize = mActivities.size();
for (int i = activitiesSize - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
- if (r.mRelaunchReason != ActivityRecord.RELAUNCH_REASON_NONE) {
+ if (r.mRelaunchReason != RELAUNCH_REASON_NONE) {
return r.mRelaunchReason;
}
}
}
- return ActivityRecord.RELAUNCH_REASON_NONE;
+ return RELAUNCH_REASON_NONE;
+ }
+
+ public long getInputDispatchingTimeout() {
+ synchronized (mAtm.mGlobalLock) {
+ return isInstrumenting() || isUsingWrapper()
+ ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS;
+ }
}
void clearProfilerIfNeeded() {
@@ -760,4 +771,9 @@
pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
}
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ if (mListener != null) {
+ mListener.writeToProto(proto, fieldId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/am/WindowProcessListener.java
index 2de3e37..9cad6fe4 100644
--- a/services/core/java/com/android/server/am/WindowProcessListener.java
+++ b/services/core/java/com/android/server/am/WindowProcessListener.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import android.content.pm.ApplicationInfo;
+import android.util.proto.ProtoOutputStream;
+
/**
* Interface used by the owner/creator of a process that owns windows to listen to changes from the
* WM side.
@@ -47,4 +50,6 @@
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
long getCpuTime();
+
+ void writeToProto(ProtoOutputStream proto, long fieldId);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cd1a7c2..f56d8e6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4682,22 +4682,15 @@
}
}
- @Override
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
- {
- mDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setHearingAidDeviceConnectionState state=" + state
- + " addr=" + device.getAddress())).printLog(TAG));
-
- setBluetoothHearingAidDeviceConnectionState(
- device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
- }
-
public int setBluetoothHearingAidDeviceConnectionState(
BluetoothDevice device, int state, boolean suppressNoisyIntent,
int musicDevice)
{
int delay;
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setHearingAidDeviceConnectionState state=" + state
+ + " addr=" + device.getAddress()
+ + " supprNoisy=" + suppressNoisyIntent)).printLog(TAG));
synchronized (mConnectedDevices) {
if (!suppressNoisyIntent) {
int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
@@ -5887,6 +5880,7 @@
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
private void onSendBecomingNoisyIntent() {
@@ -5908,7 +5902,7 @@
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
if (mDockAddress == address) {
mDockAddress = null;
}
@@ -5978,6 +5972,7 @@
sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_HEARING_AID, 0,
mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
// must be called synchronized on mConnectedDevices
@@ -5987,7 +5982,7 @@
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
// Remove Hearing Aid routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
}
// must be called synchronized on mConnectedDevices
@@ -6032,7 +6027,6 @@
} else {
makeA2dpDeviceUnavailableNow(address);
}
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
@@ -6056,7 +6050,6 @@
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
@@ -6108,25 +6101,35 @@
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceUnavailable(address);
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceAvailable(address, btDevice.getName(),
"onSetHearingAidConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
- private void setCurrentAudioRouteName(String name){
+ private void setCurrentAudioRouteNameIfPossible(String name) {
synchronized (mCurAudioRoutes) {
if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
- mCurAudioRoutes.bluetoothName = name;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
+ if (name != null || !isCurrentDeviceConnected()) {
+ mCurAudioRoutes.bluetoothName = name;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
}
}
}
+ private boolean isCurrentDeviceConnected() {
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+ if (TextUtils.equals(deviceSpec.mDeviceName, mCurAudioRoutes.bluetoothName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_DEVICES) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c16d3cd..b148a2f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -307,19 +307,19 @@
private final class CecMessageBuffer {
private List<HdmiCecMessage> mBuffer = new ArrayList<>();
- public void bufferMessage(HdmiCecMessage message) {
+ public boolean bufferMessage(HdmiCecMessage message) {
switch (message.getOpcode()) {
case Constants.MESSAGE_ACTIVE_SOURCE:
bufferActiveSource(message);
- break;
+ return true;
case Constants.MESSAGE_IMAGE_VIEW_ON:
case Constants.MESSAGE_TEXT_VIEW_ON:
bufferImageOrTextViewOn(message);
- break;
+ return true;
// Add here if new message that needs to buffer
default:
// Do not need to buffer messages other than above
- break;
+ return false;
}
}
@@ -906,10 +906,6 @@
@ServiceThreadOnly
boolean handleCecCommand(HdmiCecMessage message) {
assertRunOnServiceThread();
- if (!mAddressAllocated) {
- mCecMessageBuffer.bufferMessage(message);
- return true;
- }
int errorCode = mMessageValidator.isValid(message);
if (errorCode != HdmiCecMessageValidator.OK) {
// We'll not response on the messages with the invalid source or destination
@@ -919,7 +915,12 @@
}
return true;
}
- return dispatchMessageToLocalDevice(message);
+
+ if (dispatchMessageToLocalDevice(message)) {
+ return true;
+ }
+
+ return (!mAddressAllocated) ? mCecMessageBuffer.bufferMessage(message) : false;
}
void enableAudioReturnChannel(int portId, boolean enabled) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index d347a91..f7e871d 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -50,8 +50,7 @@
@Override
public void onSendCompleted(int error) {
if (error != SendMessageResult.SUCCESS) {
- tv().setSystemAudioMode(false);
- finish();
+ handleSystemAudioModeStatusTimeout();
}
}
});
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 4913e8b..c20079e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -197,7 +197,7 @@
private static native boolean nativeHasKeys(long ptr,
int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
- InputWindowHandle inputWindowHandle, boolean monitor);
+ InputWindowHandle inputWindowHandle, int displayId);
private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
private static native int nativeInjectInputEvent(long ptr, InputEvent event,
@@ -473,15 +473,21 @@
/**
* Creates an input channel that will receive all input from the input dispatcher.
* @param inputChannelName The input channel name.
+ * @param displayId Target display id.
* @return The input channel.
*/
- public InputChannel monitorInput(String inputChannelName) {
+ public InputChannel monitorInput(String inputChannelName, int displayId) {
if (inputChannelName == null) {
throw new IllegalArgumentException("inputChannelName must not be null.");
}
+ if (displayId < Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("displayId must >= 0.");
+ }
+
InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
- nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
+ // Register channel for monitor.
+ nativeRegisterInputChannel(mPtr, inputChannels[0], null, displayId);
inputChannels[0].dispose(); // don't need to retain the Java object reference
return inputChannels[1];
}
@@ -498,7 +504,8 @@
throw new IllegalArgumentException("inputChannel must not be null.");
}
- nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
+ // Register channel for normal.
+ nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, Display.INVALID_DISPLAY);
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 862ea9d..fc76b46 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2015,10 +2015,6 @@
}
@Override
- public void finishInput(IInputMethodClient client) {
- }
-
- @Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 0a93653..e6a018a 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -31,9 +31,11 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackagesProvider;
import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
+import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.media.RingtoneManager;
@@ -1182,12 +1184,16 @@
final int permissionGrantCount = permissionGrants.size();
for (int j = 0; j < permissionGrantCount; j++) {
DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
+ if (!isPermissionDangerous(permissionGrant.name)) {
+ Log.w(TAG, "Ignoring permission " + permissionGrant.name
+ + " which isn't dangerous");
+ continue;
+ }
if (permissions == null) {
permissions = new ArraySet<>();
} else {
permissions.clear();
}
- permissions.add(permissionGrant.name);
grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
}
}
@@ -1350,6 +1356,16 @@
&& pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
}
+ private boolean isPermissionDangerous(String name) {
+ try {
+ final PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(name, 0);
+ return (pi.getProtectionFlags() & PermissionInfo.PROTECTION_DANGEROUS) != 0;
+ } catch (NameNotFoundException e) {
+ // When unknown assume it's dangerous to be on the safe side
+ return true;
+ }
+ }
+
private static final class DefaultPermissionGrant {
final String name;
final boolean fixed;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 06ee935..dae7b01 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2061,7 +2061,8 @@
}
});
mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
- mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.registerPointerEventListener(mSystemGestures, DEFAULT_DISPLAY);
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
@@ -2258,13 +2259,16 @@
WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(mPointerLocationView, lp);
- mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView, DEFAULT_DISPLAY);
}
}
private void disablePointerLocation() {
if (mPointerLocationView != null) {
- mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView,
+ DEFAULT_DISPLAY);
WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
wm.removeView(mPointerLocationView);
mPointerLocationView = null;
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 27ab3ef..2a8e523 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -559,10 +559,10 @@
public Object getWindowManagerLock();
/** Register a system listener for touch events */
- void registerPointerEventListener(PointerEventListener listener);
+ void registerPointerEventListener(PointerEventListener listener, int displayId);
/** Unregister a system listener for touch events */
- void unregisterPointerEventListener(PointerEventListener listener);
+ void unregisterPointerEventListener(PointerEventListener listener, int displayId);
/**
* @return The content insets of the docked divider window.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 81a9ee0..7f9ee84 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -314,7 +314,6 @@
public abstract boolean showStrictModeViolationDialog();
public abstract void showSystemReadyErrorDialogsIfNeeded();
- public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
public abstract void onProcessMapped(int pid, WindowProcessController proc);
public abstract void onProcessUnMapped(int pid);
@@ -431,4 +430,13 @@
/** Called whenever an app crashes. */
public abstract void onHandleAppCrash(WindowProcessController wpc);
+
+ /**
+ * Finish the topmost activities in all stacks that belong to the crashed app.
+ * @param crashedApp The app that crashed.
+ * @param reason Reason to perform this action.
+ * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
+ */
+ public abstract int finishTopCrashedActivities(
+ WindowProcessController crashedApp, String reason);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d8fd198..ca23360 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -145,12 +145,14 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.InputChannel;
import android.view.InputDevice;
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
@@ -454,6 +456,8 @@
*/
WindowState mInputMethodWindow;
+ private final PointerEventDispatcher mPointerEventDispatcher;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final AppWindowToken atoken = w.mAppToken;
@@ -833,6 +837,15 @@
mDisplayReady = true;
mInputMonitor = new InputMonitor(service, mDisplayId);
+
+ if (mService.mInputManager != null) {
+ final InputChannel inputChannel = mService.mInputManager.monitorInput("Display "
+ + mDisplayId, mDisplayId);
+ mPointerEventDispatcher = inputChannel != null
+ ? new PointerEventDispatcher(inputChannel) : null;
+ } else {
+ mPointerEventDispatcher = null;
+ }
}
boolean isReady() {
@@ -1286,6 +1299,19 @@
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
+
+ // Tap Listeners are supported for:
+ // 1. All physical displays (multi-display).
+ // 2. VirtualDisplays on VR, AA (and everything else).
+ if (mPointerEventDispatcher != null && mTapDetector == null) {
+ if (DEBUG_DISPLAY) {
+ Slog.d(TAG,
+ "Registering PointerEventListener for DisplayId: " + mDisplayId);
+ }
+ mTapDetector = new TaskTapPointerEventListener(mService, this);
+ registerPointerEventListener(mTapDetector);
+ registerPointerEventListener(mService.mMousePositionTracker);
+ }
}
/**
@@ -2186,13 +2212,10 @@
try {
super.removeImmediately();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
- if (mService.canDispatchPointerEvents()) {
- if (mTapDetector != null) {
- mService.unregisterPointerEventListener(mTapDetector);
- }
- if (mDisplayId == DEFAULT_DISPLAY && mService.mMousePositionTracker != null) {
- mService.unregisterPointerEventListener(mService.mMousePositionTracker);
- }
+ if (mPointerEventDispatcher != null && mTapDetector != null) {
+ unregisterPointerEventListener(mTapDetector);
+ unregisterPointerEventListener(mService.mMousePositionTracker);
+ mTapDetector = null;
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
mWindowingLayer.release();
@@ -4409,4 +4432,16 @@
boolean getLastHasContent() {
return mLastHasContent;
}
+
+ void registerPointerEventListener(@NonNull PointerEventListener listener) {
+ if (mPointerEventDispatcher != null) {
+ mPointerEventDispatcher.registerInputEventListener(listener);
+ }
+ }
+
+ void unregisterPointerEventListener(@NonNull PointerEventListener listener) {
+ if (mPointerEventDispatcher != null) {
+ mPointerEventDispatcher.unregisterInputEventListener(listener);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index eeb6f6a..10d77e5 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -125,7 +125,7 @@
} else if (windowState != null) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- long timeout = mService.mAtmInternal.inputDispatchingTimedOut(
+ long timeout = mService.mAmInternal.inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3fef87d..c8977be 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -228,21 +228,6 @@
mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
displayId, dc.getDisplayInfo());
dc.configureDisplayPolicy();
-
- // Tap Listeners are supported for:
- // 1. All physical displays (multi-display).
- // 2. VirtualDisplays on VR, AA (and everything else).
- if (mService.canDispatchPointerEvents()) {
- if (DEBUG_DISPLAY) {
- Slog.d(TAG,
- "Registering PointerEventListener for DisplayId: " + displayId);
- }
- dc.mTapDetector = new TaskTapPointerEventListener(mService, dc);
- mService.registerPointerEventListener(dc.mTapDetector);
- if (displayId == DEFAULT_DISPLAY) {
- mService.registerPointerEventListener(mService.mMousePositionTracker);
- }
- }
}
return dc;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index da6bfd1..056e92e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -753,8 +753,6 @@
final ArrayMap<AnimationAdapter, SurfaceAnimator> mAnimationTransferMap = new ArrayMap<>();
final BoundsAnimationController mBoundsAnimationController;
- private final PointerEventDispatcher mPointerEventDispatcher;
-
private WindowContentFrameStats mTempWindowRenderStats;
private final LatencyTracker mLatencyTracker;
@@ -945,14 +943,6 @@
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
- if(mInputManager != null) {
- final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
- mPointerEventDispatcher = inputChannel != null
- ? new PointerEventDispatcher(inputChannel) : null;
- } else {
- mPointerEventDispatcher = null;
- }
-
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
@@ -3127,18 +3117,23 @@
}
@Override
- public void registerPointerEventListener(PointerEventListener listener) {
- mPointerEventDispatcher.registerInputEventListener(listener);
+ public void registerPointerEventListener(PointerEventListener listener, int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.registerPointerEventListener(listener);
+ }
+ }
}
@Override
- public void unregisterPointerEventListener(PointerEventListener listener) {
- mPointerEventDispatcher.unregisterInputEventListener(listener);
- }
-
- /** Check if the service is set to dispatch pointer events. */
- boolean canDispatchPointerEvents() {
- return mPointerEventDispatcher != null;
+ public void unregisterPointerEventListener(PointerEventListener listener, int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.unregisterPointerEventListener(listener);
+ }
+ }
}
// Called by window manager policy. Not exposed externally.
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 045f4eb..15a3a1a3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -99,6 +99,7 @@
"libutils",
"libhwui",
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"android.hardware.audio.common@2.0",
"android.hardware.broadcastradio@1.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c66d03c..3943dba 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -217,7 +217,7 @@
void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray);
status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
@@ -442,11 +442,11 @@
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
- const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+ const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle,
+ int32_t displayId) {
ATRACE_CALL();
- return mInputManager->getDispatcher()->registerInputChannel(
- inputChannel, inputWindowHandle, monitor);
+ return mInputManager->getDispatcher()->registerInputChannel(inputChannel, inputWindowHandle,
+ displayId);
}
status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */,
@@ -1316,7 +1316,7 @@
}
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
+ jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
@@ -1330,7 +1330,7 @@
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
- env, inputChannel, inputWindowHandle, monitor);
+ env, inputChannel, inputWindowHandle, displayId);
if (status) {
std::string message;
message += StringPrintf("Failed to register input channel. status=%d", status);
@@ -1338,7 +1338,8 @@
return;
}
- if (! monitor) {
+ // If inputWindowHandle is null and displayId >= 0, treat inputChannel as monitor.
+ if (inputWindowHandle != nullptr || displayId == ADISPLAY_ID_NONE) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
@@ -1639,7 +1640,7 @@
{ "nativeHasKeys", "(JII[I[Z)Z",
(void*) nativeHasKeys },
{ "nativeRegisterInputChannel",
- "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V",
+ "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;I)V",
(void*) nativeRegisterInputChannel },
{ "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V",
(void*) nativeUnregisterInputChannel },
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 3302dea..649f1a5 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -30,8 +30,8 @@
#include <utils/Log.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::Stats;
using android::bpf::hasBpfSupport;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index 062c044..ba64b51 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -37,6 +37,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
+import static com.android.server.am.ActivityDisplay.POSITION_TOP;
import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
import static org.junit.Assert.assertEquals;
@@ -562,23 +563,13 @@
false /* mockGetLaunchStack */);
// Create a secondary display at bottom.
- final TestActivityDisplay secondaryDisplay = spy(addNewActivityDisplayAt(POSITION_BOTTOM));
+ final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+ mSupervisor.addChild(secondaryDisplay, POSITION_BOTTOM);
final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Create an activity record on the top of secondary display.
- final ComponentName componentName = ComponentName.createRelative(
- DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_PACKAGE_NAME + ".ReusableActivity");
- final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
- .setComponent(componentName)
- .setStack(stack)
- .build();
- final ActivityRecord topActivityOnSecondaryDisplay = new ActivityBuilder(mService)
- .setComponent(componentName)
- .setLaunchMode(LAUNCH_SINGLE_TASK)
- .setTask(taskRecord)
- .build();
+ final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
// Put an activity on default display as the top focused activity.
new ActivityBuilder(mService).setCreateTask(true).build();
@@ -600,6 +591,59 @@
}
/**
+ * This test ensures that when starting an existing non-top single task activity on secondary
+ * display which is the top focused display, it should bring the task to front without creating
+ * unused stack.
+ */
+ @Test
+ public void testBringTaskToFrontOnSecondaryDisplay() {
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetLaunchStack */);
+
+ // Create a secondary display with an activity.
+ final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+ mSupervisor.addChild(secondaryDisplay, POSITION_TOP);
+ final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
+ secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */));
+
+ // Create another activity on top of the secondary display.
+ final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
+ new ActivityBuilder(mService).setTask(topTask).build();
+
+ // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
+ final ActivityOptions options = ActivityOptions.makeBasic()
+ .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
+ .setIntent(singleTaskActivity.intent)
+ .setActivityOptions(options.toBundle())
+ .execute();
+
+ // Ensure result is moving existing task to front.
+ assertEquals(START_TASK_TO_FRONT, result);
+
+ // Ensure secondary display only creates two stacks.
+ verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
+ }
+
+ private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
+ final ComponentName componentName = ComponentName.createRelative(
+ DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
+ final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+ .setComponent(componentName)
+ .setStack(stack)
+ .build();
+ return new ActivityBuilder(mService)
+ .setComponent(componentName)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setTask(taskRecord)
+ .build();
+ }
+
+ /**
* This test ensures that a reused top activity in the top focused stack is able to be
* reparented to another display.
*/
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index ea1320c..169204f 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -29,6 +29,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -97,6 +98,13 @@
mResult.reset();
}
+ @Test
+ public void testReturnsSkipWithEmptyActivity() {
+ final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ assertEquals(RESULT_SKIP, mTarget.onCalculate(task, /* layout */ null,
+ /* activity */ null, /* source */ null, /* options */ null, mCurrent, mResult));
+ }
+
// =============================
// Display ID Related Tests
// =============================
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 3dcdd23..cb8ca7e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -39,6 +39,7 @@
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doNothing;
@@ -288,34 +289,25 @@
final WindowTestUtils.TestAppWindowToken token =
WindowTestUtils.createTestAppWindowToken(dc0);
task0.addChild(token, 0);
- dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
- sWm.registerPointerEventListener(dc0.mTapDetector);
+ dc0.configureDisplayPolicy();
+ assertNotNull(dc0.mTapDetector);
+
final TaskStack stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken token1 =
WindowTestUtils.createTestAppWindowToken(dc0);
task1.addChild(token1, 0);
- dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
- sWm.registerPointerEventListener(dc1.mTapDetector);
+ dc1.configureDisplayPolicy();
+ assertNotNull(dc1.mTapDetector);
- // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
- DisplayMetrics dm0 = dc0.getDisplayMetrics();
- dc0.mTapDetector.onPointerEvent(
- createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
- dc0.mTapDetector.onPointerEvent(
- createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
-
+ // tap on primary display.
+ tapOnDisplay(dc0);
// Check focus is on primary display.
assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc0.findFocusedWindow());
- // Tap on secondary display
- DisplayMetrics dm1 = dc1.getDisplayMetrics();
- dc1.mTapDetector.onPointerEvent(
- createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
- dc1.mTapDetector.onPointerEvent(
- createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
-
+ // Tap on secondary display.
+ tapOnDisplay(dc1);
// Check focus is on secondary.
assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc1.findFocusedWindow());
@@ -626,17 +618,32 @@
return result;
}
- private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
+ private void tapOnDisplay(final DisplayContent dc) {
+ final DisplayMetrics dm = dc.getDisplayMetrics();
+ final float x = dm.widthPixels / 2;
+ final float y = dm.heightPixels / 2;
final long downTime = SystemClock.uptimeMillis();
final long eventTime = SystemClock.uptimeMillis() + 100;
- final int metaState = 0;
-
- return MotionEvent.obtain(
+ // sending ACTION_DOWN
+ final MotionEvent downEvent = MotionEvent.obtain(
downTime,
- eventTime,
- isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
+ downTime,
+ MotionEvent.ACTION_DOWN,
x,
y,
- metaState);
+ 0 /*metaState*/);
+ downEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(downEvent);
+
+ // sending ACTION_UP
+ final MotionEvent upEvent = MotionEvent.obtain(
+ downTime,
+ eventTime,
+ MotionEvent.ACTION_UP,
+ x,
+ y,
+ 0 /*metaState*/);
+ upEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(upEvent);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 54fd7db..389eba5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -34,8 +34,8 @@
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.view.InputChannel;
-
-import androidx.test.InstrumentationRegistry;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import com.android.server.LocalServices;
import com.android.server.input.InputManagerService;
@@ -46,6 +46,12 @@
import org.junit.runners.model.Statement;
import org.mockito.invocation.InvocationOnMock;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+
/**
* A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
* to properly tear it down after.
@@ -61,6 +67,12 @@
private WindowManagerService mService;
private TestWindowManagerPolicy mPolicy;
+ // Record all {@link SurfaceControl.Transaction} created while testing and releases native
+ // resources when test finishes.
+ private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
+ // Record all {@link SurfaceControl} created while testing and releases native resources when
+ // test finishes.
+ private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>();
@Override
public Statement apply(Statement base, Description description) {
@@ -108,12 +120,25 @@
// InputChannel is final and can't be mocked.
InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
if (input != null && input.length > 1) {
- doReturn(input[1]).when(ims).monitorInput(anyString());
+ doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
}
mService = WindowManagerService.main(context, ims, false,
false, mPolicy = new TestWindowManagerPolicy(
WindowManagerServiceRule.this::getWindowManagerService));
+ mService.mTransactionFactory = () -> {
+ final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ mSurfaceTransactions.add(new WeakReference<>(transaction));
+ return transaction;
+ };
+ mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) {
+ @Override
+ public SurfaceControl build() {
+ final SurfaceControl control = super.build();
+ mSurfaceControls.add(new WeakReference<>(control));
+ return control;
+ }
+ };
mService.onInitReady();
@@ -135,6 +160,8 @@
private void tearDown() {
waitUntilWindowManagerHandlersIdle();
+ destroyAllSurfaceTransactions();
+ destroyAllSurfaceControls();
removeServices();
mService = null;
mPolicy = null;
@@ -158,4 +185,24 @@
SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
}
}
+
+ private void destroyAllSurfaceTransactions() {
+ for (final WeakReference<Transaction> reference : mSurfaceTransactions) {
+ final Transaction transaction = reference.get();
+ if (transaction != null) {
+ reference.clear();
+ transaction.close();
+ }
+ }
+ }
+
+ private void destroyAllSurfaceControls() {
+ for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
+ final SurfaceControl control = reference.get();
+ if (control != null) {
+ reference.clear();
+ control.destroy();
+ }
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index a610e6e..3a8c4ae 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -98,10 +98,13 @@
super(s);
}
+ @Override
public SurfaceControl.Builder setParent(SurfaceControl sc) {
mPendingParent = sc;
return super.setParent(sc);
}
+
+ @Override
public SurfaceControl build() {
SurfaceControl sc = super.build();
mParentFor.put(sc, mPendingParent);
@@ -110,7 +113,7 @@
}
}
- class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+ private class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
public SurfaceControl.Builder make(SurfaceSession s) {
return new HierarchyRecorder(s);
}
@@ -131,6 +134,7 @@
@After
public void after() {
mTransaction.close();
+ mParentFor.keySet().forEach(SurfaceControl::destroy);
mParentFor.clear();
}
diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
index 5bf94af..32fc796 100644
--- a/services/usb/java/com/android/server/usb/UsbSerialReader.java
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -75,14 +75,21 @@
if (uid != Process.SYSTEM_UID) {
enforcePackageBelongsToUid(uid, packageName);
- PackageInfo pkg;
+ int packageTargetSdkVersion;
+ long token = Binder.clearCallingIdentity();
try {
- pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RemoteException("package " + packageName + " cannot be found");
+ PackageInfo pkg;
+ try {
+ pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RemoteException("package " + packageName + " cannot be found");
+ }
+ packageTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+ if (packageTargetSdkVersion >= Build.VERSION_CODES.Q) {
if (mContext.checkPermission(android.Manifest.permission.MANAGE_USB, pid, uid)
== PackageManager.PERMISSION_DENIED) {
UsbUserSettingsManager settings = mSettingsManager.getSettingsForUser(
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 8454d12..1efa906 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3524,6 +3524,18 @@
public static final String CARRIER_ID = "carrier_id";
/**
+ * A unique mno carrier id. mno carrier shares the same {@link All#MCCMNC} as carrier id
+ * and can be solely identified by {@link All#MCCMNC} only. If there is no such mno
+ * carrier, then mno carrier id equals to {@link #CARRIER_ID carrier id}.
+ *
+ * <p>mno carrier id can be used as fallback id. When the exact carrier id configurations
+ * are not found, usually fall back to its mno carrier id.
+ * <P>Type: INTEGER </P>
+ * @hide
+ */
+ public static final String MNO_CARRIER_ID = "mno_carrier_id";
+
+ /**
* Contains mappings between matching rules with carrier id for all carriers.
* @hide
*/
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fac1943..b0997f1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1202,6 +1202,20 @@
"always_show_data_rat_icon_bool";
/**
+ * Boolean indicating if default data account should show LTE or 4G icon
+ * @hide
+ */
+ public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL =
+ "show_4g_for_lte_data_icon_bool";
+
+ /**
+ * Boolean indicating if lte+ icon should be shown if available
+ * @hide
+ */
+ public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL =
+ "hide_lte_plus_data_icon_bool";
+
+ /**
* Boolean to decide whether to show precise call failed cause to user
* @hide
*/
@@ -1965,6 +1979,31 @@
public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
/**
+ * Indicates if the carrier supports auto-upgrading a call to RTT when receiving a call from a
+ * RTT-supported device.
+ * @hide
+ */
+ public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
+
+ /**
+ * Indicates if the carrier supports RTT during a video call.
+ * @hide
+ */
+ public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+
+ /**
+ * Indicates if the carrier supports upgrading a voice call to an RTT call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
+
+ /**
+ * Indicates if the carrier supports downgrading a RTT call to a voice call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
+
+ /**
* The flag to disable the popup dialog which warns the user of data charges.
* @hide
*/
@@ -2505,6 +2544,8 @@
sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false);
sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
+ sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true);
+ sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8f78c34..d6a0ae1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1163,6 +1163,16 @@
public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
/**
+ * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
+ * the updated mno carrier id of the current subscription.
+ * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
+ * the carrier cannot be identified.
+ *
+ *@hide
+ */
+ public static final String EXTRA_MNO_CARRIER_ID = "android.telephony.extra.MNO_CARRIER_ID";
+
+ /**
* An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
* indicates the updated carrier name of the current subscription.
* {@see TelephonyManager#getSimCarrierIdName()}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index eb144f9..aabefe3 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -257,7 +257,7 @@
private final int mProfileId;
- private final boolean mModemCognitive;
+ private final boolean mPersistent;
private final int mMaxConns;
private final int mWaitTime;
private final int mMaxConnsTime;
@@ -290,13 +290,13 @@
}
/**
- * Returns if the APN setting is to be set in modem.
+ * Returns if the APN setting is persistent on the modem.
*
* @return is the APN setting to be set in modem
* @hide
*/
- public boolean getModemCognitive() {
- return mModemCognitive;
+ public boolean isPersistent() {
+ return mPersistent;
}
/**
@@ -616,7 +616,7 @@
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
- this.mModemCognitive = builder.mModemCognitive;
+ this.mPersistent = builder.mModemCognitive;
this.mMaxConns = builder.mMaxConns;
this.mWaitTime = builder.mWaitTime;
this.mMaxConnsTime = builder.mMaxConnsTime;
@@ -740,7 +740,7 @@
apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
- apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
+ apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime,
apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
}
@@ -947,7 +947,7 @@
sb.append(", ").append(PROTOCOL_INT_MAP.get(mRoamingProtocol));
sb.append(", ").append(mCarrierEnabled);
sb.append(", ").append(mProfileId);
- sb.append(", ").append(mModemCognitive);
+ sb.append(", ").append(mPersistent);
sb.append(", ").append(mMaxConns);
sb.append(", ").append(mWaitTime);
sb.append(", ").append(mMaxConnsTime);
@@ -1029,7 +1029,7 @@
&& Objects.equals(mMmsc, other.mMmsc)
&& Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
&& Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort,other.mProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
&& Objects.equals(mUser, other.mUser)
&& Objects.equals(mPassword, other.mPassword)
&& Objects.equals(mAuthType, other.mAuthType)
@@ -1038,7 +1038,7 @@
&& Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
+ && Objects.equals(mPersistent, other.mPersistent)
&& Objects.equals(mMaxConns, other.mMaxConns)
&& Objects.equals(mWaitTime, other.mWaitTime)
&& Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
@@ -1080,11 +1080,11 @@
&& Objects.equals(mPassword, other.mPassword)
&& Objects.equals(mAuthType, other.mAuthType)
&& Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
+ && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
&& (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
+ && Objects.equals(mPersistent, other.mPersistent)
&& Objects.equals(mMaxConns, other.mMaxConns)
&& Objects.equals(mWaitTime, other.mWaitTime)
&& Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index e8597b2..da4822c 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -68,17 +68,15 @@
private final int mMtu;
- private final String mMvnoType;
+ private final boolean mPersistent;
- private final String mMvnoMatchData;
+ private final boolean mPreferred;
- private final boolean mModemCognitive;
-
- public DataProfile(int profileId, String apn, String protocol, int authType,
- String userName, String password, int type, int maxConnsTime, int maxConns,
- int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
- int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
- boolean modemCognitive) {
+ /** @hide */
+ public DataProfile(int profileId, String apn, String protocol, int authType, String userName,
+ String password, int type, int maxConnsTime, int maxConns, int waitTime,
+ boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+ int bearerBitmap, int mtu, boolean persistent, boolean preferred) {
this.mProfileId = profileId;
this.mApn = apn;
@@ -100,11 +98,11 @@
this.mRoamingProtocol = roamingProtocol;
this.mBearerBitmap = bearerBitmap;
this.mMtu = mtu;
- this.mMvnoType = mvnoType;
- this.mMvnoMatchData = mvnoMatchData;
- this.mModemCognitive = modemCognitive;
+ this.mPersistent = persistent;
+ this.mPreferred = preferred;
}
+ /** @hide */
public DataProfile(Parcel source) {
mProfileId = source.readInt();
mApn = source.readString();
@@ -121,9 +119,8 @@
mRoamingProtocol = source.readString();
mBearerBitmap = source.readInt();
mMtu = source.readInt();
- mMvnoType = source.readString();
- mMvnoMatchData = source.readString();
- mModemCognitive = source.readBoolean();
+ mPersistent = source.readBoolean();
+ mPreferred = source.readBoolean();
}
/**
@@ -207,23 +204,17 @@
public int getMtu() { return mMtu; }
/**
- * @return The MVNO type: possible values are "imsi", "gid", "spn".
+ * @return {@code true} if modem must persist this data profile.
*/
- public String getMvnoType() { return mMvnoType; }
+ public boolean isPersistent() { return mPersistent; }
/**
- * @return The MVNO match data. For example,
- * SPN: A MOBILE, BEN NL, ...
- * IMSI: 302720x94, 2060188, ...
- * GID: 4E, 33, ...
+ * @return {@code true} if this data profile was used to bring up the last default
+ * (i.e internet) data connection successfully.
*/
- public String getMvnoMatchData() { return mMvnoMatchData; }
+ public boolean isPreferred() { return mPreferred; }
- /**
- * @return True if the data profile was sent to the modem through setDataProfile earlier.
- */
- public boolean isModemCognitive() { return mModemCognitive; }
-
+ /** @hide */
@Override
public int describeContents() {
return 0;
@@ -233,11 +224,11 @@
public String toString() {
return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+ "/" + (Build.IS_USER ? "***/***/***" :
- (mApn + "/" + mUserName + "/" + mPassword))
- + "/" + mType + "/" + mMaxConnsTime
- + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
- + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
- + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+ (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
+ + mMaxConnsTime + "/" + mMaxConns + "/"
+ + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/"
+ + mRoamingProtocol + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
+ + mPreferred;
}
@Override
@@ -246,6 +237,7 @@
return (o == this || toString().equals(o.toString()));
}
+ /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mProfileId);
@@ -263,11 +255,11 @@
dest.writeString(mRoamingProtocol);
dest.writeInt(mBearerBitmap);
dest.writeInt(mMtu);
- dest.writeString(mMvnoType);
- dest.writeString(mMvnoMatchData);
- dest.writeBoolean(mModemCognitive);
+ dest.writeBoolean(mPersistent);
+ dest.writeBoolean(mPreferred);
}
+ /** @hide */
public static final Parcelable.Creator<DataProfile> CREATOR =
new Parcelable.Creator<DataProfile>() {
@Override
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index d6a08543..bdba8c8 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -33,7 +33,7 @@
* A parcelable class that wraps and retrieves the information of number, service category(s) and
* country code for a specific emergency number.
*/
-public final class EmergencyNumber implements Parcelable {
+public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNumber> {
private static final String LOG_TAG = "EmergencyNumber";
@@ -235,20 +235,22 @@
}
/**
- * Returns the bitmask of emergency service categories {@link EmergencyServiceCategories} of
- * the emergency number.
+ * Returns the bitmask of emergency service categories of the emergency number.
*
- * @return bitmask of the emergency service categories {@link EmergencyServiceCategories}
+ * @return bitmask of the emergency service categories
*/
public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
return mEmergencyServiceCategoryBitmask;
}
/**
- * Returns the emergency service categories {@link EmergencyServiceCategories} of the emergency
- * number.
+ * Returns the emergency service categories of the emergency number.
*
- * @return a list of the emergency service categories {@link EmergencyServiceCategories}
+ * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} is returned and it means the number is in
+ * all categories.
+ *
+ * @return a list of the emergency service categories
*/
public List<Integer> getEmergencyServiceCategories() {
List<Integer> categories = new ArrayList<>();
@@ -276,34 +278,37 @@
}
/**
- * Checks if the emergency number is in the specified emergency service category(s)
- * {@link EmergencyServiceCategories}.
+ * Checks if the emergency number is in the supplied emergency service category(s).
+ *
+ * @param categories - the supplied emergency service categories
*
* @return {@code true} if the emergency number is in the specified emergency service
- * category(s) {@link EmergencyServiceCategories}; {@code false} otherwise.
- *
- * @param categories - emergency service categories {@link EmergencyServiceCategories}
+ * category(s) or if its emergency service category is
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
*/
public boolean isInEmergencyServiceCategories(@EmergencyServiceCategories int categories) {
if (categories == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED) {
return serviceUnspecified();
}
+ if (serviceUnspecified()) {
+ return true;
+ }
return (mEmergencyServiceCategoryBitmask & categories) == categories;
}
/**
- * Returns the bitmask of the sources {@link EmergencyNumberSources} of the emergency number.
+ * Returns the bitmask of the sources of the emergency number.
*
- * @return bitmask of the emergency number sources {@link EmergencyNumberSources}
+ * @return bitmask of the emergency number sources
*/
public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
return mEmergencyNumberSourceBitmask;
}
/**
- * Returns a list of {@link EmergencyNumberSources} of the emergency number.
+ * Returns a list of sources of the emergency number.
*
- * @return a list of {@link EmergencyNumberSources}
+ * @return a list of emergency number sources
*/
public List<Integer> getEmergencyNumberSources() {
List<Integer> sources = new ArrayList<>();
@@ -316,13 +321,12 @@
}
/**
- * Checks if the emergency number is from the specified emergency number source(s)
- * {@link EmergencyNumberSources}.
+ * Checks if the emergency number is from the specified emergency number source(s).
*
* @return {@code true} if the emergency number is from the specified emergency number
- * source(s) {@link EmergencyNumberSources}; {@code false} otherwise.
+ * source(s); {@code false} otherwise.
*
- * @param sources - {@link EmergencyNumberSources}
+ * @param sources - the supplied emergency number sources
*/
public boolean isFromSources(@EmergencyNumberSources int sources) {
return (mEmergencyNumberSourceBitmask & sources) == sources;
@@ -359,6 +363,62 @@
return (o == this || toString().equals(o.toString()));
}
+ /**
+ * Calculate the score for display priority.
+ *
+ * A higher display priority score means the emergency number has a higher display priority.
+ * The score is higher if the source is defined for a higher display priority.
+ *
+ * The priority of sources are defined as follows:
+ * EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING >
+ * EMERGENCY_NUMBER_SOURCE_SIM >
+ * EMERGENCY_NUMBER_SOURCE_DEFAULT >
+ * EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG
+ *
+ */
+ private int getDisplayPriorityScore() {
+ int score = 0;
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING)) {
+ score += 1 << 4;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) {
+ score += 1 << 3;
+ }
+ // TODO add a score if the number comes from Google's emergency number database
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) {
+ score += 1 << 1;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG)) {
+ score += 1 << 0;
+ }
+ return score;
+ }
+
+ /**
+ * Compare the display priority for this emergency number and the supplied emergency number.
+ *
+ * @param emergencyNumber the supplied emergency number
+ * @return a negative value if the supplied emergency number has a lower display priority;
+ * a positive value if the supplied emergency number has a higher display priority;
+ * 0 if both have equal display priority.
+ */
+ @Override
+ public int compareTo(EmergencyNumber emergencyNumber) {
+ if (this.getDisplayPriorityScore()
+ > emergencyNumber.getDisplayPriorityScore()) {
+ return -1;
+ } else if (this.getDisplayPriorityScore()
+ < emergencyNumber.getDisplayPriorityScore()) {
+ return 1;
+ } else {
+ /**
+ * TODO if both numbers have the same display priority score, the number matches the
+ * Google's emergency number database has a higher display priority.
+ */
+ return 0;
+ }
+ }
+
public static final Parcelable.Creator<EmergencyNumber> CREATOR =
new Parcelable.Creator<EmergencyNumber>() {
@Override
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index 8d18ae8..f2d0cbf 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -16,22 +16,19 @@
package android.telephony.ims;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Log;
import android.telephony.Rlog;
-/*
- * This file contains all the api's through which
- * information received in Dialog Event Package can be
- * queried
- */
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
- * Parcelable object to handle MultiEndpoint Dialog Information
+ * Parcelable object to handle MultiEndpoint Dialog Event Package Information.
* @hide
*/
@SystemApi
@@ -40,8 +37,39 @@
private static final String TAG = "ImsExternalCallState";
// Dialog States
+ /**
+ * The external call is in the confirmed dialog state.
+ */
public static final int CALL_STATE_CONFIRMED = 1;
+ /**
+ * The external call is in the terminated dialog state.
+ */
public static final int CALL_STATE_TERMINATED = 2;
+
+ /**@hide*/
+ @IntDef(flag = true,
+ value = {
+ CALL_STATE_CONFIRMED,
+ CALL_STATE_TERMINATED
+ },
+ prefix = "CALL_STATE_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExternalCallState {}
+
+ /**@hide*/
+ @IntDef(flag = true,
+ value = {
+ ImsCallProfile.CALL_TYPE_VOICE,
+ ImsCallProfile.CALL_TYPE_VT_TX,
+ ImsCallProfile.CALL_TYPE_VT_RX,
+ ImsCallProfile.CALL_TYPE_VT
+ },
+ prefix = "CALL_TYPE_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExternalCallType {}
+
+
+
// Dialog Id
private int mCallId;
// Number
@@ -58,10 +86,9 @@
public ImsExternalCallState() {
}
- /** @hide */
- @UnsupportedAppUsage
- public ImsExternalCallState(int callId, Uri address, boolean isPullable, int callState,
- int callType, boolean isCallheld) {
+ /**@hide*/
+ public ImsExternalCallState(int callId, Uri address, boolean isPullable,
+ @ExternalCallState int callState, int callType, boolean isCallheld) {
mCallId = callId;
mAddress = address;
mIsPullable = isPullable;
@@ -71,9 +98,10 @@
Rlog.d(TAG, "ImsExternalCallState = " + this);
}
- /** @hide */
+ /**@hide*/
public ImsExternalCallState(int callId, Uri address, Uri localAddress,
- boolean isPullable, int callState, int callType, boolean isCallheld) {
+ boolean isPullable, @ExternalCallState int callState, int callType,
+ boolean isCallheld) {
mCallId = callId;
mAddress = address;
mLocalAddress = localAddress;
@@ -84,6 +112,31 @@
Rlog.d(TAG, "ImsExternalCallState = " + this);
}
+ /**
+ * Create a new ImsExternalCallState instance to contain Multiendpoint Dialog information.
+ * @param callId The unique ID of the call, which will be used to identify this external
+ * connection.
+ * @param address A {@link Uri} containing the remote address of this external connection.
+ * @param localAddress A {@link Uri} containing the local address information.
+ * @param isPullable A flag determining if this external connection can be pulled to the current
+ * device.
+ * @param callState The state of the external call.
+ * @param callType The type of external call.
+ * @param isCallheld A flag determining if the external connection is currently held.
+ */
+ public ImsExternalCallState(String callId, Uri address, Uri localAddress,
+ boolean isPullable, @ExternalCallState int callState, @ExternalCallType int callType,
+ boolean isCallheld) {
+ mCallId = getIdForString(callId);
+ mAddress = address;
+ mLocalAddress = localAddress;
+ mIsPullable = isPullable;
+ mCallState = callState;
+ mCallType = callType;
+ mIsHeld = isCallheld;
+ Rlog.d(TAG, "ImsExternalCallState = " + this);
+ }
+
/** @hide */
public ImsExternalCallState(Parcel in) {
mCallId = in.readInt();
@@ -135,7 +188,9 @@
return mAddress;
}
- /** @hide */
+ /**
+ * @return A {@link Uri} containing the local address from the Multiendpoint Dialog Information.
+ */
public Uri getLocalAddress() {
return mLocalAddress;
}
@@ -144,11 +199,11 @@
return mIsPullable;
}
- public int getCallState() {
+ public @ExternalCallState int getCallState() {
return mCallState;
}
- public int getCallType() {
+ public @ExternalCallType int getCallType() {
return mCallType;
}
@@ -166,4 +221,15 @@
", mCallType = " + mCallType +
", mIsHeld = " + mIsHeld + "}";
}
+
+ private int getIdForString(String idString) {
+ try {
+ return Integer.parseInt(idString);
+ } catch (NumberFormatException e) {
+ // In the case that there are alphanumeric characters, we will create a hash of the
+ // String value as a backup.
+ // TODO: Modify call IDs to use Strings as keys instead of integers in telephony/telecom
+ return idString.hashCode();
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 86cb1b7..b0c875e 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -100,6 +100,7 @@
public static final int EVENT_DATA_RECONNECT = BASE + 47;
public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+ public static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = BASE + 50;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 9730ebc..eda8e77 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -44,10 +45,6 @@
private static final boolean DBG = false;
- // When set to true this flag will treat all apps that fail the device identifier check as
- // though they are targeting pre-Q and return dummy data instead of throwing a SecurityException
- private static final boolean RELAX_DEVICE_IDENTIFIER_CHECK = true;
-
private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
@@ -280,23 +277,29 @@
*/
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
- // if the device identifier check is relaxed then just return false to return dummy data to
- // the caller instead of throwing a SecurityException for apps targeting Q+.
- if (RELAX_DEVICE_IDENTIFIER_CHECK) {
- Log.wtf(LOG_TAG,
- "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
- return false;
+ Log.wtf(LOG_TAG,
+ "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
+ // if the device identifier check is relaxed then revert to the READ_PHONE_STATE permission
+ // check that was previously required to access device identifiers.
+ boolean relaxDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 0;
+ if (relaxDeviceIdentifierCheck) {
+ return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
} else {
+ boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
if (callingPackage != null) {
try {
- // if the target SDK is pre-Q then check if the calling package would have
- // previously had access to device identifiers.
+ // if the target SDK is pre-Q or the target Q behavior is disabled then check if
+ // the calling package would have previously had access to device identifiers.
ApplicationInfo callingPackageInfo =
context.getPackageManager().getApplicationInfo(
callingPackage, 0);
- if (callingPackageInfo != null
- && callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
- if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE,
+ if (callingPackageInfo != null && (
+ callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
+ || targetQBehaviorDisabled)) {
+ if (context.checkPermission(
+ android.Manifest.permission.READ_PHONE_STATE,
pid,
uid) == PackageManager.PERMISSION_GRANTED) {
return false;
@@ -312,8 +315,8 @@
// default to throwing the SecurityException.
}
}
- throw new SecurityException(message + ": The user " + uid + " does not have the "
- + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
+ throw new SecurityException(message + ": The user " + uid
+ + " does not meet the requirements to access device identifiers.");
}
}
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index a20b9b7..b353ff0 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -35,6 +35,43 @@
namespace aapt {
+static ApkFormat DetermineApkFormat(io::IFileCollection* apk) {
+ if (apk->FindFile(kApkResourceTablePath) != nullptr) {
+ return ApkFormat::kBinary;
+ } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) {
+ return ApkFormat::kProto;
+ } else {
+ // If the resource table is not present, attempt to read the manifest.
+ io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ return ApkFormat::kUnknown;
+ }
+
+ // First try in proto format.
+ std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ if (manifest_in != nullptr) {
+ pb::XmlNode pb_node;
+ io::ProtoInputStreamReader proto_reader(manifest_in.get());
+ if (proto_reader.ReadMessage(&pb_node)) {
+ return ApkFormat::kProto;
+ }
+ }
+
+ // If it didn't work, try in binary format.
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data != nullptr) {
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
+ if (manifest != nullptr) {
+ return ApkFormat::kBinary;
+ }
+ }
+
+ return ApkFormat::kUnknown;
+ }
+}
+
std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
Source source(path);
std::string error;
@@ -301,41 +338,4 @@
return doc;
}
-ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) {
- if (apk->FindFile(kApkResourceTablePath) != nullptr) {
- return ApkFormat::kBinary;
- } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) {
- return ApkFormat::kProto;
- } else {
- // If the resource table is not present, attempt to read the manifest.
- io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath);
- if (manifest_file == nullptr) {
- return ApkFormat::kUnknown;
- }
-
- // First try in proto format.
- std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
- if (manifest_in != nullptr) {
- pb::XmlNode pb_node;
- io::ProtoInputStreamReader proto_reader(manifest_in.get());
- if (!proto_reader.ReadMessage(&pb_node)) {
- return ApkFormat::kProto;
- }
- }
-
- // If it didn't work, try in binary format.
- std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
- if (manifest_data != nullptr) {
- std::string error;
- std::unique_ptr<xml::XmlResource> manifest =
- xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
- if (manifest != nullptr) {
- return ApkFormat::kBinary;
- }
- }
-
- return ApkFormat::kUnknown;
- }
-}
-
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 84c57c1..5b6f45e 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -121,8 +121,6 @@
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
ApkFormat format_;
-
- static ApkFormat DetermineApkFormat(io::IFileCollection* apk);
};
} // namespace aapt
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
new file mode 100755
index 0000000..48c0755
--- /dev/null
+++ b/tools/hiddenapi/merge_csv.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Merge mutliple CSV files, possibly with different columns, writing to stdout.
+"""
+
+import csv
+import sys
+
+csv_readers = [
+ csv.DictReader(open(csv_file, 'rb'), delimiter=',', quotechar='|')
+ for csv_file in sys.argv[1:]
+]
+
+# Build union of all columns from source files:
+headers = set()
+for reader in csv_readers:
+ headers = headers.union(reader.fieldnames)
+
+# Concatenate all files to output:
+out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', fieldnames = sorted(headers))
+out.writeheader()
+for reader in csv_readers:
+ for row in reader:
+ out.writerow(row)
+
+