summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--api/system-current.txt17
-rw-r--r--api/test-current.txt19
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp42
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h1
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp107
-rw-r--r--core/java/android/net/IpPrefix.java2
-rw-r--r--core/java/android/net/LinkAddress.java4
-rw-r--r--core/java/android/net/LinkProperties.java5
-rw-r--r--core/java/android/net/Network.java2
-rw-r--r--core/java/android/net/apf/ApfCapabilities.java4
-rw-r--r--core/java/android/net/shared/FdEventsReader.java (renamed from packages/NetworkStack/src/android/net/util/FdEventsReader.java)24
-rw-r--r--core/java/android/net/util/SocketUtils.java73
-rw-r--r--core/java/android/os/GraphicsEnvironment.java33
-rw-r--r--core/java/android/provider/Settings.java18
-rw-r--r--core/java/android/view/IDisplayFoldListener.aidl26
-rw-r--r--core/java/android/view/IWindowManager.aidl11
-rw-r--r--core/proto/android/app/settings_enums.proto4
-rw-r--r--core/proto/android/providers/settings/global.proto20
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java8
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java2
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpClient.java82
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java378
-rw-r--r--packages/NetworkStack/src/android/net/util/PacketReader.java1
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkObserver.java5
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java44
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkStackService.java8
-rw-r--r--packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java41
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java16
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto4
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java9
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java13
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java4
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldController.java155
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java30
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/utils/WmDisplayCutout.java5
-rw-r--r--telephony/java/com/android/ims/internal/uce/common/StatusCode.java4
-rw-r--r--telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl74
-rw-r--r--telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java50
44 files changed, 1226 insertions, 174 deletions
diff --git a/Android.bp b/Android.bp
index d89b5013df12..7ce8b31e42c2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -375,6 +375,7 @@ java_defaults {
"core/java/android/view/IApplicationToken.aidl",
"core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl",
"core/java/android/view/IDockedStackListener.aidl",
+ "core/java/android/view/IDisplayFoldListener.aidl",
"core/java/android/view/IGraphicsStats.aidl",
"core/java/android/view/IGraphicsStatsCallback.aidl",
"core/java/android/view/IInputFilter.aidl",
diff --git a/api/system-current.txt b/api/system-current.txt
index f405eaf54c65..82bafab9aacc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4095,6 +4095,7 @@ package android.net {
public final class IpPrefix implements android.os.Parcelable {
ctor public IpPrefix(java.net.InetAddress, int);
+ ctor public IpPrefix(String);
}
public final class IpSecManager {
@@ -4117,6 +4118,7 @@ package android.net {
ctor public LinkAddress(java.net.InetAddress, int, int, int);
ctor public LinkAddress(java.net.InetAddress, int);
ctor public LinkAddress(String);
+ ctor public LinkAddress(String, int, int);
method public boolean isGlobalPreferred();
method public boolean isIPv4();
method public boolean isIPv6();
@@ -4127,6 +4129,7 @@ package android.net {
ctor public LinkProperties();
ctor public LinkProperties(android.net.LinkProperties);
method public boolean addDnsServer(java.net.InetAddress);
+ method public boolean addLinkAddress(android.net.LinkAddress);
method public boolean addRoute(android.net.RouteInfo);
method public void clear();
method @Nullable public android.net.IpPrefix getNat64Prefix();
@@ -4141,6 +4144,7 @@ package android.net {
method public boolean isProvisioned();
method public boolean isReachable(java.net.InetAddress);
method public boolean removeDnsServer(java.net.InetAddress);
+ method public boolean removeLinkAddress(android.net.LinkAddress);
method public boolean removeRoute(android.net.RouteInfo);
method public void setDnsServers(java.util.Collection<java.net.InetAddress>);
method public void setDomains(String);
@@ -4157,6 +4161,7 @@ package android.net {
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -4292,8 +4297,8 @@ package android.net.apf {
public class ApfCapabilities {
ctor public ApfCapabilities(int, int, int);
- method public boolean getApfDrop8023Frames(android.content.Context);
- method public int[] getApfEthTypeBlackList(android.content.Context);
+ method public static boolean getApfDrop8023Frames(android.content.Context);
+ method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
field public final int apfPacketFormat;
field public final int apfVersionSupported;
@@ -4490,11 +4495,19 @@ package android.net.metrics {
package android.net.util {
public class SocketUtils {
+ method public static void addArpEntry(java.net.Inet4Address, android.net.MacAddress, String, java.io.FileDescriptor) throws java.io.IOException;
+ method public static void attachControlPacketFilter(java.io.FileDescriptor, int) throws java.net.SocketException;
+ method public static void attachDhcpFilter(java.io.FileDescriptor) throws java.net.SocketException;
+ method public static void attachRaFilter(java.io.FileDescriptor, int) throws java.net.SocketException;
+ method public static void bindSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException;
method public static void closeSocket(java.io.FileDescriptor) throws java.io.IOException;
+ method public static void connectSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
method public static java.net.SocketAddress makePacketSocketAddress(short, int);
method public static java.net.SocketAddress makePacketSocketAddress(int, byte[]);
+ method public static void sendTo(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+ method public static void setSocketTimeValueOption(java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 2295a21bf109..9c27535664fe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -812,6 +812,7 @@ package android.net {
public final class IpPrefix implements android.os.Parcelable {
ctor public IpPrefix(java.net.InetAddress, int);
+ ctor public IpPrefix(String);
}
public final class IpSecManager {
@@ -820,6 +821,9 @@ package android.net {
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(java.net.InetAddress, int, int, int);
+ ctor public LinkAddress(java.net.InetAddress, int);
+ ctor public LinkAddress(String);
+ ctor public LinkAddress(String, int, int);
method public boolean isGlobalPreferred();
method public boolean isIPv4();
method public boolean isIPv6();
@@ -829,6 +833,7 @@ package android.net {
public final class LinkProperties implements android.os.Parcelable {
ctor public LinkProperties(android.net.LinkProperties);
method public boolean addDnsServer(java.net.InetAddress);
+ method public boolean addLinkAddress(android.net.LinkAddress);
method @Nullable public android.net.IpPrefix getNat64Prefix();
method public java.util.List<java.net.InetAddress> getPcscfServers();
method public String getTcpBufferSizes();
@@ -841,6 +846,7 @@ package android.net {
method public boolean isProvisioned();
method public boolean isReachable(java.net.InetAddress);
method public boolean removeDnsServer(java.net.InetAddress);
+ method public boolean removeLinkAddress(android.net.LinkAddress);
method public boolean removeRoute(android.net.RouteInfo);
method public void setNat64Prefix(android.net.IpPrefix);
method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
@@ -851,6 +857,7 @@ package android.net {
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -902,8 +909,8 @@ package android.net.apf {
public class ApfCapabilities {
ctor public ApfCapabilities(int, int, int);
- method public boolean getApfDrop8023Frames(android.content.Context);
- method public int[] getApfEthTypeBlackList(android.content.Context);
+ method public static boolean getApfDrop8023Frames(android.content.Context);
+ method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
field public final int apfPacketFormat;
field public final int apfVersionSupported;
@@ -1100,11 +1107,19 @@ package android.net.metrics {
package android.net.util {
public class SocketUtils {
+ method public static void addArpEntry(java.net.Inet4Address, android.net.MacAddress, String, java.io.FileDescriptor) throws java.io.IOException;
+ method public static void attachControlPacketFilter(java.io.FileDescriptor, int) throws java.net.SocketException;
+ method public static void attachDhcpFilter(java.io.FileDescriptor) throws java.net.SocketException;
+ method public static void attachRaFilter(java.io.FileDescriptor, int) throws java.net.SocketException;
+ method public static void bindSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException;
method public static void closeSocket(java.io.FileDescriptor) throws java.io.IOException;
+ method public static void connectSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
method public static java.net.SocketAddress makePacketSocketAddress(short, int);
method public static java.net.SocketAddress makePacketSocketAddress(int, byte[]);
+ method public static void sendTo(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+ method public static void setSocketTimeValueOption(java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 4122d8440959..5645461cc3ab 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -524,6 +524,14 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
multiIntervals.resize(mFieldMatchers.size());
}
+ // We only use anomaly detection under certain cases.
+ // N.B.: The anomaly detection cases were modified in order to fix an issue with value metrics
+ // containing multiple values. We tried to retain all previous behaviour, but we are unsure the
+ // previous behaviour was correct. At the time of the fix, anomaly detection had no owner.
+ // Whoever next works on it should look into the cases where it is triggered in this function.
+ // Discussion here: http://ag/6124370.
+ bool useAnomalyDetection = true;
+
for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
const Matcher& matcher = mFieldMatchers[i];
Interval& interval = multiIntervals[i];
@@ -546,7 +554,11 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
// no base. just update base and return.
interval.base = value;
interval.hasBase = true;
- return;
+ // If we're missing a base, do not use anomaly detection on incomplete data
+ useAnomalyDetection = false;
+ // Continue (instead of return) here in order to set interval.base and
+ // interval.hasBase for other intervals
+ continue;
}
}
Value diff;
@@ -560,7 +572,9 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
VLOG("Unexpected decreasing value");
StatsdStats::getInstance().notePullDataError(mPullTagId);
interval.base = value;
- return;
+ // If we've got bad data, do not use anomaly detection
+ useAnomalyDetection = false;
+ continue;
}
break;
case ValueMetric::DECREASING:
@@ -572,7 +586,9 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
VLOG("Unexpected increasing value");
StatsdStats::getInstance().notePullDataError(mPullTagId);
interval.base = value;
- return;
+ // If we've got bad data, do not use anomaly detection
+ useAnomalyDetection = false;
+ continue;
}
break;
case ValueMetric::ANY:
@@ -608,14 +624,18 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIn
interval.sampleSize += 1;
}
- // TODO: propgate proper values down stream when anomaly support doubles
- long wholeBucketVal = multiIntervals[0].value.long_value;
- auto prev = mCurrentFullBucket.find(eventKey);
- if (prev != mCurrentFullBucket.end()) {
- wholeBucketVal += prev->second;
- }
- for (auto& tracker : mAnomalyTrackers) {
- tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
+ // Only trigger the tracker if all intervals are correct
+ if (useAnomalyDetection) {
+ // TODO: propgate proper values down stream when anomaly support doubles
+ long wholeBucketVal = multiIntervals[0].value.long_value;
+ auto prev = mCurrentFullBucket.find(eventKey);
+ if (prev != mCurrentFullBucket.end()) {
+ wholeBucketVal += prev->second;
+ }
+ for (auto& tracker : mAnomalyTrackers) {
+ tracker->detectAndDeclareAnomaly(
+ eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
+ }
}
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 69eb0afaf7c4..a8dfc5ba0e5d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -212,6 +212,7 @@ private:
FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
+ FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 9cfe3436ada7..c0648ee70032 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1508,6 +1508,113 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
}
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_value_field()->add_child()->set_field(3);
+ metric.set_aggregation_type(ValueMetric::MIN);
+ metric.set_use_diff(true);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event1->write(1);
+ event1->write(10);
+ event1->write(20);
+ event1->init();
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+ event2->write(1);
+ event2->write(15);
+ event2->write(22);
+ event2->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval0 =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval1 =
+ valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ EXPECT_EQ(true, curInterval0.hasBase);
+ EXPECT_EQ(10, curInterval0.base.long_value);
+ EXPECT_EQ(false, curInterval0.hasValue);
+ EXPECT_EQ(true, curInterval1.hasBase);
+ EXPECT_EQ(20, curInterval1.base.long_value);
+ EXPECT_EQ(false, curInterval1.hasValue);
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ EXPECT_EQ(true, curInterval0.hasValue);
+ EXPECT_EQ(5, curInterval0.value.long_value);
+ EXPECT_EQ(true, curInterval1.hasValue);
+ EXPECT_EQ(2, curInterval1.value.long_value);
+
+ // no change in first value field
+ shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+ event3->write(1);
+ event3->write(15);
+ event3->write(25);
+ event3->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ EXPECT_EQ(true, curInterval0.hasBase);
+ EXPECT_EQ(15, curInterval0.base.long_value);
+ EXPECT_EQ(true, curInterval0.hasValue);
+ EXPECT_EQ(true, curInterval1.hasBase);
+ EXPECT_EQ(25, curInterval1.base.long_value);
+ EXPECT_EQ(true, curInterval1.hasValue);
+
+ shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
+ event4->write(1);
+ event4->write(15);
+ event4->write(29);
+ event4->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ EXPECT_EQ(true, curInterval0.hasBase);
+ EXPECT_EQ(15, curInterval0.base.long_value);
+ EXPECT_EQ(true, curInterval0.hasValue);
+ EXPECT_EQ(true, curInterval1.hasBase);
+ EXPECT_EQ(29, curInterval1.base.long_value);
+ EXPECT_EQ(true, curInterval1.hasValue);
+
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+
+ EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
+ EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
+ EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
+
+ EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
+}
+
/*
* Tests zero default base.
*/
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b996cdab5164..175263f0adaa 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -104,6 +104,8 @@ public final class IpPrefix implements Parcelable {
*
* @hide
*/
+ @SystemApi
+ @TestApi
public IpPrefix(String prefix) {
// We don't reuse the (InetAddress, int) constructor because "error: call to this must be
// first statement in constructor". We could factor out setting the member variables to an
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index fbd602c7b2d0..8d779aaa2312 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -176,6 +176,7 @@ public class LinkAddress implements Parcelable {
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(InetAddress address, int prefixLength) {
this(address, prefixLength, 0, 0);
this.scope = scopeForUnicastAddress(address);
@@ -199,6 +200,7 @@ public class LinkAddress implements Parcelable {
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(String address) {
this(address, 0, 0);
this.scope = scopeForUnicastAddress(this.address);
@@ -212,6 +214,8 @@ public class LinkAddress implements Parcelable {
* @param scope The address scope.
* @hide
*/
+ @SystemApi
+ @TestApi
public LinkAddress(String address, int flags, int scope) {
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 662870182eea..42db0fd7cb8c 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -287,7 +287,8 @@ public final class LinkProperties implements Parcelable {
* @return true if {@code address} was added or updated, false otherwise.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @TestApi
public boolean addLinkAddress(LinkAddress address) {
if (address == null) {
return false;
@@ -315,6 +316,8 @@ public final class LinkProperties implements Parcelable {
* @return true if the address was removed, false if it did not exist.
* @hide
*/
+ @SystemApi
+ @TestApi
public boolean removeLinkAddress(LinkAddress toRemove) {
int i = findLinkAddressIndex(toRemove);
if (i >= 0) {
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 2c831de72051..e04b5fc5f9cf 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -123,6 +123,8 @@ public class Network implements Parcelable {
/**
* @hide
*/
+ @SystemApi
+ @TestApi
public Network(Network that) {
this(that.netId, that.mPrivateDnsBypass);
}
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index baf5585589f1..e09fa8fd9e77 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -81,14 +81,14 @@ public class ApfCapabilities {
/**
* @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
*/
- public boolean getApfDrop8023Frames(Context context) {
+ public static boolean getApfDrop8023Frames(Context context) {
return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
}
/**
* @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped.
*/
- public int[] getApfEthTypeBlackList(Context context) {
+ public static int[] getApfEthTypeBlackList(Context context) {
return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
}
}
diff --git a/packages/NetworkStack/src/android/net/util/FdEventsReader.java b/core/java/android/net/shared/FdEventsReader.java
index 8bbf449f6374..5ccc560a3091 100644
--- a/packages/NetworkStack/src/android/net/util/FdEventsReader.java
+++ b/core/java/android/net/shared/FdEventsReader.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package android.net.util;
+package android.net.shared;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -63,6 +63,7 @@ import java.io.FileDescriptor;
* All public methods MUST only be called from the same thread with which
* the Handler constructor argument is associated.
*
+ * @param <BufferType> the type of the buffer used to read data.
* @hide
*/
public abstract class FdEventsReader<BufferType> {
@@ -89,6 +90,7 @@ public abstract class FdEventsReader<BufferType> {
mBuffer = buffer;
}
+ /** Start this FdEventsReader. */
public void start() {
if (onCorrectThread()) {
createAndRegisterFd();
@@ -100,6 +102,7 @@ public abstract class FdEventsReader<BufferType> {
}
}
+ /** Stop this FdEventsReader and destroy the file descriptor. */
public void stop() {
if (onCorrectThread()) {
unregisterAndDestroyFd();
@@ -112,18 +115,25 @@ public abstract class FdEventsReader<BufferType> {
}
@NonNull
- public Handler getHandler() { return mHandler; }
+ public Handler getHandler() {
+ return mHandler;
+ }
protected abstract int recvBufSize(@NonNull BufferType buffer);
- public int recvBufSize() { return recvBufSize(mBuffer); }
+ /** Returns the size of the receive buffer. */
+ public int recvBufSize() {
+ return recvBufSize(mBuffer);
+ }
/**
* Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}.
*
* <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0.
*/
- public final long numPacketsReceived() { return mPacketsReceived; }
+ public final long numPacketsReceived() {
+ return mPacketsReceived;
+ }
/**
* Subclasses MUST create the listening socket here, including setting
@@ -199,7 +209,9 @@ public abstract class FdEventsReader<BufferType> {
onStart();
}
- private boolean isRunning() { return (mFd != null) && mFd.valid(); }
+ private boolean isRunning() {
+ return (mFd != null) && mFd.valid();
+ }
// Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error.
private boolean handleInput() {
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 2df08a1c5ba1..fbb15ed693d9 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -21,17 +21,21 @@ import static android.system.OsConstants.SO_BINDTODEVICE;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.net.MacAddress;
import android.net.NetworkUtils;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.Os;
import android.system.PacketSocketAddress;
+import android.system.StructTimeval;
import libcore.io.IoBridge;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.net.Inet4Address;
import java.net.SocketAddress;
+import java.net.SocketException;
/**
* Collection of utilities to interact with raw sockets.
@@ -76,11 +80,80 @@ public class SocketUtils {
}
/**
+ * Set an option on a socket that takes a time value argument.
+ */
+ public static void setSocketTimeValueOption(
+ FileDescriptor fd, int level, int option, long millis) throws ErrnoException {
+ Os.setsockoptTimeval(fd, level, option, StructTimeval.fromMillis(millis));
+ }
+
+ /**
+ * Bind a socket to the specified address.
+ */
+ public static void bindSocket(FileDescriptor fd, SocketAddress addr)
+ throws ErrnoException, SocketException {
+ Os.bind(fd, addr);
+ }
+
+ /**
+ * Connect a socket to the specified address.
+ */
+ public static void connectSocket(FileDescriptor fd, SocketAddress addr)
+ throws ErrnoException, SocketException {
+ Os.connect(fd, addr);
+ }
+
+ /**
+ * Send a message on a socket, using the specified SocketAddress.
+ */
+ public static void sendTo(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount,
+ int flags, SocketAddress addr) throws ErrnoException, SocketException {
+ Os.sendto(fd, bytes, byteOffset, byteCount, flags, addr);
+ }
+
+ /**
* @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
*/
public static void closeSocket(FileDescriptor fd) throws IOException {
IoBridge.closeAndSignalBlockedThreads(fd);
}
+ /**
+ * Attaches a socket filter that accepts DHCP packets to the given socket.
+ */
+ public static void attachDhcpFilter(FileDescriptor fd) throws SocketException {
+ NetworkUtils.attachDhcpFilter(fd);
+ }
+
+ /**
+ * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param packetType the hardware address type, one of ARPHRD_*.
+ */
+ public static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException {
+ NetworkUtils.attachRaFilter(fd, packetType);
+ }
+
+ /**
+ * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
+ *
+ * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
+ *
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param packetType the hardware address type, one of ARPHRD_*.
+ */
+ public static void attachControlPacketFilter(FileDescriptor fd, int packetType)
+ throws SocketException {
+ NetworkUtils.attachControlPacketFilter(fd, packetType);
+ }
+
+ /**
+ * Add an entry into the ARP cache.
+ */
+ public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname,
+ FileDescriptor fd) throws IOException {
+ NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
+ }
+
private SocketUtils() {}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index efcad3ece97d..93360a5fa377 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -63,7 +63,7 @@ public class GraphicsEnvironment {
private static final boolean DEBUG = false;
private static final String TAG = "GraphicsEnvironment";
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
- private static final String GUP_WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
@@ -529,44 +529,45 @@ public class GraphicsEnvironment {
return;
}
- // GUP_DEV_ALL_APPS
+ // GAME_DRIVER_ALL_APPS
// 0: Default (Invalid values fallback to default as well)
// 1: All apps use Game Driver
// 2: All apps use system graphics driver
- int gupDevAllApps = coreSettings.getInt(Settings.Global.GUP_DEV_ALL_APPS, 0);
- if (gupDevAllApps == 2) {
+ int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
+ if (gameDriverAllApps == 2) {
if (DEBUG) {
- Log.w(TAG, "GUP is turned off on this device");
+ Log.w(TAG, "Game Driver is turned off on this device");
}
return;
}
- if (gupDevAllApps != 1) {
- // GUP_DEV_OPT_OUT_APPS has higher priority than GUP_DEV_OPT_IN_APPS
- if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
+ if (gameDriverAllApps != 1) {
+ // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
+ if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
.contains(ai.packageName)) {
if (DEBUG) {
- Log.w(TAG, ai.packageName + " opts out from GUP.");
+ Log.w(TAG, ai.packageName + " opts out from Game Driver.");
}
return;
}
- boolean isDevOptIn = getGlobalSettingsString(coreSettings,
- Settings.Global.GUP_DEV_OPT_IN_APPS)
- .contains(ai.packageName);
+ boolean isOptIn =
+ getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
+ .contains(ai.packageName);
- if (!isDevOptIn && !onWhitelist(context, driverPackageName, ai.packageName)) {
+ if (!isOptIn && !onWhitelist(context, driverPackageName, ai.packageName)) {
if (DEBUG) {
Log.w(TAG, ai.packageName + " is not on the whitelist.");
}
return;
}
- if (!isDevOptIn) {
+ if (!isOptIn) {
// At this point, the application is on the whitelist only, check whether it's
// on the blacklist, terminate early when it's on the blacklist.
try {
// TODO(b/121350991) Switch to DeviceConfig with property listener.
- String base64String = coreSettings.getString(Settings.Global.GUP_BLACKLIST);
+ String base64String =
+ coreSettings.getString(Settings.Global.GAME_DRIVER_BLACKLIST);
if (base64String != null && !base64String.isEmpty()) {
Blacklists blacklistsProto = Blacklists.parseFrom(
Base64.decode(base64String, BASE64_FLAGS));
@@ -652,7 +653,7 @@ public class GraphicsEnvironment {
Context driverContext = context.createPackageContext(driverPackageName,
Context.CONTEXT_RESTRICTED);
AssetManager assets = driverContext.getAssets();
- InputStream stream = assets.open(GUP_WHITELIST_FILENAME);
+ InputStream stream = assets.open(GAME_DRIVER_WHITELIST_FILENAME);
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
for (String packageName; (packageName = reader.readLine()) != null; ) {
if (packageName.equals(applicationPackageName)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 290b5560474b..a7af5d191c17 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12241,33 +12241,33 @@ public final class Settings {
"angle_whitelist";
/**
- * Game Update Package global preference for all Apps.
+ * Game Driver global preference for all Apps.
* 0 = Default
- * 1 = All Apps use Game Update Package
+ * 1 = All Apps use Game Driver
* 2 = All Apps use system graphics driver
* @hide
*/
- public static final String GUP_DEV_ALL_APPS = "gup_dev_all_apps";
+ public static final String GAME_DRIVER_ALL_APPS = "game_driver_all_apps";
/**
- * List of Apps selected to use Game Update Package.
+ * List of Apps selected to use Game Driver.
* i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
- public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps";
+ public static final String GAME_DRIVER_OPT_IN_APPS = "game_driver_opt_in_apps";
/**
- * List of Apps selected not to use Game Update Package.
+ * List of Apps selected not to use Game Driver.
* i.e. <pkg1>,<pkg2>,...,<pkgN>
* @hide
*/
- public static final String GUP_DEV_OPT_OUT_APPS = "gup_dev_opt_out_apps";
+ public static final String GAME_DRIVER_OPT_OUT_APPS = "game_driver_opt_out_apps";
/**
- * Apps on the blacklist that are forbidden to use Game Update Package.
+ * Apps on the blacklist that are forbidden to use Game Driver.
* @hide
*/
- public static final String GUP_BLACKLIST = "gup_blacklist";
+ public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
/**
* Apps on the whitelist that are allowed to use Game Driver.
diff --git a/core/java/android/view/IDisplayFoldListener.aidl b/core/java/android/view/IDisplayFoldListener.aidl
new file mode 100644
index 000000000000..2c91149dfc1b
--- /dev/null
+++ b/core/java/android/view/IDisplayFoldListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * {@hide}
+ */
+oneway interface IDisplayFoldListener
+{
+ /** Called when the foldedness of a display changes */
+ void onDisplayFoldChanged(int displayId, boolean folded);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 42ac8801629f..8ae4757f5de6 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -34,6 +34,7 @@ import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
+import android.view.IDisplayFoldListener;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
@@ -403,6 +404,16 @@ interface IWindowManager
Region getCurrentImeTouchRegion();
/**
+ * Registers an IDisplayFoldListener.
+ */
+ void registerDisplayFoldListener(IDisplayFoldListener listener);
+
+ /**
+ * Unregisters an IDisplayFoldListener.
+ */
+ void unregisterDisplayFoldListener(IDisplayFoldListener listener);
+
+ /**
* Starts a window trace.
*/
void startWindowTrace();
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index eb716ac280e2..94a6734b69c8 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2157,10 +2157,10 @@ enum PageId {
// OS: Q
ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
- // OPEN: Settings > Developer Options > Game Update Packages
+ // OPEN: Settings > Developer Options > Game Driver Preferences
// CATEGORY: SETTINGS
// OS: Q
- SETTINGS_GUP_DASHBOARD = 1613;
+ SETTINGS_GAME_DRIVER_DASHBOARD = 1613;
// OPEN: Settings > Accessibility > Vibration > Ring vibration
// CATEGORY: SETTINGS
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 7e7942e6ddf1..66cd1094825a 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -436,20 +436,20 @@ message GlobalSettingsProto {
// Ordered GPU debug layer list for GLES
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers_gles = 7;
- // GUP - Game Update Package global preference for all Apps
+ // Game Driver - global preference for all Apps
// 0 = Default
- // 1 = All Apps use Game Update Package
+ // 1 = All Apps use Game Driver
// 2 = All Apps use system graphics driver
- optional SettingProto gup_dev_all_apps = 8;
- // GUP - List of Apps selected to use Game Update Package
+ optional SettingProto game_driver_all_apps = 8;
+ // Game Driver - List of Apps selected to use Game Driver
// i.e. <pkg1>,<pkg2>,...,<pkgN>
- optional SettingProto gup_dev_opt_in_apps = 9;
- // GUP - List of Apps selected not to use Game Update Package
+ optional SettingProto game_driver_opt_in_apps = 9;
+ // Game Driver - List of Apps selected not to use Game Driver
// i.e. <pkg1>,<pkg2>,...,<pkgN>
- optional SettingProto gup_dev_opt_out_apps = 10;
- // GUP - List of Apps that are forbidden to use Game Update Package
- optional SettingProto gup_blacklist = 11;
- // List of Apps that are allowed to use Game Driver package.
+ optional SettingProto game_driver_opt_out_apps = 10;
+ // Game Driver - List of Apps that are forbidden to use Game Driver
+ optional SettingProto game_driver_blacklist = 11;
+ // Game Driver - List of Apps that are allowed to use Game Driver
optional SettingProto game_driver_whitelist = 12;
// ANGLE - List of Apps that can check ANGLE rules
optional SettingProto angle_whitelist = 13;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c05795de4751..1db8135d31c7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -861,6 +861,11 @@
The default is false. -->
<bool name="config_lidControlsSleep">false</bool>
+ <!-- Indicate whether closing the lid causes the device to enter the folded state which means
+ to get a smaller screen and opening the lid causes the device to enter the unfolded state
+ which means to get a larger screen. -->
+ <bool name="config_lidControlsDisplayFold">false</bool>
+
<!-- Desk dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a desk dock.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 47bd9da65870..aefa9dfd1056 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3532,6 +3532,7 @@
<java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
<java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
+ <java-symbol type="bool" name="config_lidControlsDisplayFold" />
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 605c219072bc..ca2e3ed0b5ab 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -486,10 +486,10 @@ public class SettingsBackupTest {
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
- Settings.Global.GUP_DEV_ALL_APPS,
- Settings.Global.GUP_DEV_OPT_IN_APPS,
- Settings.Global.GUP_DEV_OPT_OUT_APPS,
- Settings.Global.GUP_BLACKLIST,
+ Settings.Global.GAME_DRIVER_ALL_APPS,
+ Settings.Global.GAME_DRIVER_OPT_IN_APPS,
+ Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+ Settings.Global.GAME_DRIVER_BLACKLIST,
Settings.Global.GAME_DRIVER_WHITELIST,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
index dce8b619494e..eac8d2a3b410 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
@@ -18,7 +18,7 @@ package android.net.dhcp;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.util.FdEventsReader;
+import android.net.shared.FdEventsReader;
import android.os.Handler;
import android.system.Os;
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index f20e01636d72..4315d34ba447 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -40,15 +40,12 @@ import android.net.ip.IIpClientCallbacks;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.net.shared.InitialConfiguration;
-import android.net.shared.NetdService;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
import android.net.util.SharedLog;
import android.os.ConditionVariable;
-import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -64,7 +61,7 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
-import com.android.server.net.NetlinkTracker;
+import com.android.server.NetworkObserverRegistry;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -338,8 +335,9 @@ public class IpClient extends StateMachine {
private final Dependencies mDependencies;
private final CountDownLatch mShutdownLatch;
private final ConnectivityManager mCm;
- private final INetworkManagementService mNwService;
- private final NetlinkTracker mNetlinkTracker;
+ private final INetd mNetd;
+ private final NetworkObserverRegistry mObserverRegistry;
+ private final IpClientLinkObserver mLinkObserver;
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
private final SharedLog mLog;
@@ -373,15 +371,6 @@ public class IpClient extends StateMachine {
private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
public static class Dependencies {
- public INetworkManagementService getNMS() {
- return INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
- }
-
- public INetd getNetd() {
- return NetdService.getInstance();
- }
-
/**
* Get interface parameters for the specified interface.
*/
@@ -390,26 +379,14 @@ public class IpClient extends StateMachine {
}
}
- public IpClient(Context context, String ifName, IIpClientCallbacks callback) {
- this(context, ifName, callback, new Dependencies());
- }
-
- /**
- * An expanded constructor, useful for dependency injection.
- * TODO: migrate all test users to mock IpClient directly and remove this ctor.
- */
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
- INetworkManagementService nwService) {
- this(context, ifName, callback, new Dependencies() {
- @Override
- public INetworkManagementService getNMS() {
- return nwService;
- }
- });
+ NetworkObserverRegistry observerRegistry) {
+ this(context, ifName, callback, observerRegistry, new Dependencies());
}
@VisibleForTesting
- IpClient(Context context, String ifName, IIpClientCallbacks callback, Dependencies deps) {
+ IpClient(Context context, String ifName, IIpClientCallbacks callback,
+ NetworkObserverRegistry observerRegistry, Dependencies deps) {
super(IpClient.class.getSimpleName() + "." + ifName);
Preconditions.checkNotNull(ifName);
Preconditions.checkNotNull(callback);
@@ -422,7 +399,7 @@ public class IpClient extends StateMachine {
mDependencies = deps;
mShutdownLatch = new CountDownLatch(1);
mCm = mContext.getSystemService(ConnectivityManager.class);
- mNwService = deps.getNMS();
+ mObserverRegistry = observerRegistry;
sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
mLog = sSmLogs.get(mInterfaceName);
@@ -433,19 +410,15 @@ public class IpClient extends StateMachine {
// TODO: Consider creating, constructing, and passing in some kind of
// InterfaceController.Dependencies class.
- mInterfaceCtrl = new InterfaceController(mInterfaceName, deps.getNetd(), mLog);
+ mNetd = mContext.getSystemService(INetd.class);
+ mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
- mNetlinkTracker = new NetlinkTracker(
+ mLinkObserver = new IpClientLinkObserver(
mInterfaceName,
- new NetlinkTracker.Callback() {
- @Override
- public void update() {
- sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
- }
- }) {
+ () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
@Override
- public void interfaceAdded(String iface) {
- super.interfaceAdded(iface);
+ public void onInterfaceAdded(String iface) {
+ super.onInterfaceAdded(iface);
if (mClatInterfaceName.equals(iface)) {
mCallback.setNeighborDiscoveryOffload(false);
} else if (!mInterfaceName.equals(iface)) {
@@ -457,8 +430,8 @@ public class IpClient extends StateMachine {
}
@Override
- public void interfaceRemoved(String iface) {
- super.interfaceRemoved(iface);
+ public void onInterfaceRemoved(String iface) {
+ super.onInterfaceRemoved(iface);
// TODO: Also observe mInterfaceName going down and take some
// kind of appropriate action.
if (mClatInterfaceName.equals(iface)) {
@@ -570,19 +543,11 @@ public class IpClient extends StateMachine {
}
private void startStateMachineUpdaters() {
- try {
- mNwService.registerObserver(mNetlinkTracker);
- } catch (RemoteException e) {
- logError("Couldn't register NetlinkTracker: %s", e);
- }
+ mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver);
}
private void stopStateMachineUpdaters() {
- try {
- mNwService.unregisterObserver(mNetlinkTracker);
- } catch (RemoteException e) {
- logError("Couldn't unregister NetlinkTracker: %s", e);
- }
+ mObserverRegistry.unregisterObserver(mLinkObserver);
}
@Override
@@ -805,7 +770,7 @@ public class IpClient extends StateMachine {
// we should only call this if we know for sure that there are no IP addresses
// assigned to the interface, etc.
private void resetLinkProperties() {
- mNetlinkTracker.clearLinkProperties();
+ mLinkObserver.clearLinkProperties();
mConfiguration = null;
mDhcpResults = null;
mTcpBufferSizes = "";
@@ -984,10 +949,10 @@ public class IpClient extends StateMachine {
// - IPv6 DNS servers
//
// N.B.: this is fundamentally race-prone and should be fixed by
- // changing NetlinkTracker from a hybrid edge/level model to an
+ // changing IpClientLinkObserver from a hybrid edge/level model to an
// edge-only model, or by giving IpClient its own netlink socket(s)
// so as to track all required information directly.
- LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
+ LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
newLp.addRoute(route);
@@ -1166,8 +1131,7 @@ public class IpClient extends StateMachine {
// necessary or does reading from settings at startup suffice?).
final int numSolicits = 5;
final int interSolicitIntervalMs = 750;
- setNeighborParameters(mDependencies.getNetd(), mInterfaceName,
- numSolicits, interSolicitIntervalMs);
+ setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs);
} catch (Exception e) {
mLog.e("Failed to adjust neighbor parameters", e);
// Carry on using the system defaults (currently: 3, 1000);
diff --git a/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
new file mode 100644
index 000000000000..8ad99aa0399a
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+package android.net.ip;
+
+import android.net.InetAddresses;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+import android.util.Log;
+
+import com.android.server.NetworkObserver;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Keeps track of link configuration received from Netd.
+ *
+ * An instance of this class is constructed by passing in an interface name and a callback. The
+ * owner is then responsible for registering the tracker with NetworkObserverRegistry. When the
+ * class receives update notifications, it applies the update to its local LinkProperties, and if
+ * something has changed, notifies its owner of the update via the callback.
+ *
+ * The owner can then call {@code getLinkProperties()} in order to find out
+ * what changed. If in the meantime the LinkProperties stored here have changed,
+ * this class will return the current LinkProperties. Because each change
+ * triggers an update callback after the change is made, the owner may get more
+ * callbacks than strictly necessary (some of which may be no-ops), but will not
+ * be out of sync once all callbacks have been processed.
+ *
+ * Threading model:
+ *
+ * - The owner of this class is expected to create it, register it, and call
+ * getLinkProperties or clearLinkProperties on its thread.
+ * - Most of the methods in the class are implementing NetworkObserver and are called
+ * on the handler used to register the observer.
+ * - All accesses to mLinkProperties must be synchronized(this). All the other
+ * member variables are immutable once the object is constructed.
+ *
+ * @hide
+ */
+public class IpClientLinkObserver implements NetworkObserver {
+ private final String mTag;
+
+ /**
+ * Callback used by {@link IpClientLinkObserver} to send update notifications.
+ */
+ public interface Callback {
+ /**
+ * Called when some properties of the link were updated.
+ */
+ void update();
+ }
+
+ private final String mInterfaceName;
+ private final Callback mCallback;
+ private final LinkProperties mLinkProperties;
+ private DnsServerRepository mDnsServerRepository;
+
+ private static final boolean DBG = false;
+
+ public IpClientLinkObserver(String iface, Callback callback) {
+ mTag = "NetlinkTracker/" + iface;
+ mInterfaceName = iface;
+ mCallback = callback;
+ mLinkProperties = new LinkProperties();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+ mDnsServerRepository = new DnsServerRepository();
+ }
+
+ private void maybeLog(String operation, String iface, LinkAddress address) {
+ if (DBG) {
+ Log.d(mTag, operation + ": " + address + " on " + iface
+ + " flags " + address.getFlags() + " scope " + address.getScope());
+ }
+ }
+
+ private void maybeLog(String operation, Object o) {
+ if (DBG) {
+ Log.d(mTag, operation + ": " + o.toString());
+ }
+ }
+
+ @Override
+ public void onInterfaceRemoved(String iface) {
+ maybeLog("interfaceRemoved", iface);
+ if (mInterfaceName.equals(iface)) {
+ // Our interface was removed. Clear our LinkProperties and tell our owner that they are
+ // now empty. Note that from the moment that the interface is removed, any further
+ // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
+ // code that parses them will not be able to resolve the ifindex to an interface name.
+ clearLinkProperties();
+ mCallback.update();
+ }
+ }
+
+ @Override
+ public void onInterfaceAddressUpdated(LinkAddress address, String iface) {
+ if (mInterfaceName.equals(iface)) {
+ maybeLog("addressUpdated", iface, address);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.addLinkAddress(address);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void onInterfaceAddressRemoved(LinkAddress address, String iface) {
+ if (mInterfaceName.equals(iface)) {
+ maybeLog("addressRemoved", iface, address);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.removeLinkAddress(address);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void onRouteUpdated(RouteInfo route) {
+ if (mInterfaceName.equals(route.getInterface())) {
+ maybeLog("routeUpdated", route);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.addRoute(route);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void onRouteRemoved(RouteInfo route) {
+ if (mInterfaceName.equals(route.getInterface())) {
+ maybeLog("routeRemoved", route);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.removeRoute(route);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
+ if (mInterfaceName.equals(iface)) {
+ maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
+ boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
+ if (changed) {
+ synchronized (this) {
+ mDnsServerRepository.setDnsServersOn(mLinkProperties);
+ }
+ mCallback.update();
+ }
+ }
+ }
+
+ /**
+ * Returns a copy of this object's LinkProperties.
+ */
+ public synchronized LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
+ }
+
+ /**
+ * Reset this object's LinkProperties.
+ */
+ public synchronized void clearLinkProperties() {
+ // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
+ // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
+ // mLinkProperties, as desired.
+ mDnsServerRepository = new DnsServerRepository();
+ mLinkProperties.clear();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+ }
+
+ /**
+ * Tracks DNS server updates received from Netlink.
+ *
+ * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
+ * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be
+ * used any more. In this way, the network can gracefully migrate clients from one set of DNS
+ * servers to another. Announcements can both raise and lower the lifetime, and an announcement
+ * can expire servers by announcing them with a lifetime of zero.
+ *
+ * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of
+ * DNS servers at any given time. These are referred to as the current servers. In case all the
+ * current servers expire, the class also keeps track of a larger (but limited) number of
+ * servers that are promoted to current servers when the current ones expire. In order to
+ * minimize updates to the rest of the system (and potentially expensive cache flushes) this
+ * class attempts to keep the list of current servers constant where possible. More
+ * specifically, the list of current servers is only updated if a new server is learned and
+ * there are not yet {@code NUM_CURRENT_SERVERS} current servers, or if one or more of the
+ * current servers expires or is pushed out of the set. Therefore, the current servers will not
+ * necessarily be the ones with the highest lifetime, but the ones learned first.
+ *
+ * This is by design: if instead the class always preferred the servers with the highest
+ * lifetime, a (misconfigured?) network where two or more routers announce more than
+ * {@code NUM_CURRENT_SERVERS} unique servers would cause persistent oscillations.
+ *
+ * TODO: Currently servers are only expired when a new DNS update is received.
+ * Update them using timers, or possibly on every notification received by NetlinkTracker.
+ *
+ * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
+ * notifications are sent by multiple threads. If future threads use alarms to expire, those
+ * alarms must also be synchronized(this).
+ *
+ */
+ private static class DnsServerRepository {
+
+ /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
+ static final int NUM_CURRENT_SERVERS = 3;
+
+ /** How many DNS servers we'll keep track of, in total. */
+ static final int NUM_SERVERS = 12;
+
+ /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
+ private Set<InetAddress> mCurrentServers;
+
+ public static final String TAG = "DnsServerRepository";
+
+ /**
+ * Stores all the DNS servers we know about, for use when the current servers expire.
+ * Always sorted in order of decreasing expiry. The elements in this list are also the
+ * values of mIndex, and may be elements in mCurrentServers.
+ */
+ private ArrayList<DnsServerEntry> mAllServers;
+
+ /**
+ * Indexes the servers so we can update their lifetimes more quickly in the common case
+ * where servers are not being added, but only being refreshed.
+ */
+ private HashMap<InetAddress, DnsServerEntry> mIndex;
+
+ DnsServerRepository() {
+ mCurrentServers = new HashSet<>();
+ mAllServers = new ArrayList<>(NUM_SERVERS);
+ mIndex = new HashMap<>(NUM_SERVERS);
+ }
+
+ /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
+ public synchronized void setDnsServersOn(LinkProperties lp) {
+ lp.setDnsServers(mCurrentServers);
+ }
+
+ /**
+ * Notifies the class of new DNS server information.
+ * @param lifetime the time in seconds that the DNS servers are valid.
+ * @param addresses the string representations of the IP addresses of DNS servers to use.
+ */
+ public synchronized boolean addServers(long lifetime, String[] addresses) {
+ // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
+ // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
+ // (136 years) is close enough.
+ long now = System.currentTimeMillis();
+ long expiry = now + 1000 * lifetime;
+
+ // Go through the list of servers. For each one, update the entry if one exists, and
+ // create one if it doesn't.
+ for (String addressString : addresses) {
+ InetAddress address;
+ try {
+ address = InetAddresses.parseNumericAddress(addressString);
+ } catch (IllegalArgumentException ex) {
+ continue;
+ }
+
+ if (!updateExistingEntry(address, expiry)) {
+ // There was no entry for this server. Create one, unless it's already expired
+ // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
+ if (expiry > now) {
+ DnsServerEntry entry = new DnsServerEntry(address, expiry);
+ mAllServers.add(entry);
+ mIndex.put(address, entry);
+ }
+ }
+ }
+
+ // Sort the servers by expiry.
+ Collections.sort(mAllServers);
+
+ // Prune excess entries and update the current server list.
+ return updateCurrentServers();
+ }
+
+ private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
+ DnsServerEntry existing = mIndex.get(address);
+ if (existing != null) {
+ existing.expiry = expiry;
+ return true;
+ }
+ return false;
+ }
+
+ private synchronized boolean updateCurrentServers() {
+ long now = System.currentTimeMillis();
+ boolean changed = false;
+
+ // Prune excess or expired entries.
+ for (int i = mAllServers.size() - 1; i >= 0; i--) {
+ if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
+ DnsServerEntry removed = mAllServers.remove(i);
+ mIndex.remove(removed.address);
+ changed |= mCurrentServers.remove(removed.address);
+ } else {
+ break;
+ }
+ }
+
+ // Add servers to the current set, in order of decreasing lifetime, until it has enough.
+ // Prefer existing servers over new servers in order to minimize updates to the rest of
+ // the system and avoid persistent oscillations.
+ for (DnsServerEntry entry : mAllServers) {
+ if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
+ changed |= mCurrentServers.add(entry.address);
+ } else {
+ break;
+ }
+ }
+ return changed;
+ }
+ }
+
+ /**
+ * Represents a DNS server entry with an expiry time.
+ *
+ * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
+ * The ordering of entries with the same lifetime is unspecified, because given two servers with
+ * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
+ * faster than comparing the IP address as well.
+ *
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ */
+ private static class DnsServerEntry implements Comparable<DnsServerEntry> {
+ /** The IP address of the DNS server. */
+ public final InetAddress address;
+ /** The time until which the DNS server may be used. A Java millisecond time as might be
+ * returned by currentTimeMillis(). */
+ public long expiry;
+
+ DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
+ this.address = address;
+ this.expiry = expiry;
+ }
+
+ public int compareTo(DnsServerEntry other) {
+ return Long.compare(other.expiry, this.expiry);
+ }
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java
index 4aec6b6753a6..94b1e9f2e14e 100644
--- a/packages/NetworkStack/src/android/net/util/PacketReader.java
+++ b/packages/NetworkStack/src/android/net/util/PacketReader.java
@@ -18,6 +18,7 @@ package android.net.util;
import static java.lang.Math.max;
+import android.net.shared.FdEventsReader;
import android.os.Handler;
import android.system.Os;
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserver.java b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
index d3b40a67633d..cccec0bb5d40 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkObserver.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.net.LinkAddress;
+import android.net.RouteInfo;
/**
* Observer for network events, to use with {@link NetworkObserverRegistry}.
@@ -77,11 +78,11 @@ public interface NetworkObserver {
* @see android.net.INetdUnsolicitedEventListener
* #onRouteChanged(boolean, String, String, String)
*/
- default void onRouteUpdated(String route, String gateway, String ifName) {}
+ default void onRouteUpdated(RouteInfo route) {}
/**
* @see android.net.INetdUnsolicitedEventListener
* #onRouteChanged(boolean, String, String, String)
*/
- default void onRouteRemoved(String route, String gateway, String ifName) {}
+ default void onRouteRemoved(RouteInfo route) {}
}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
index 14e6c5fdadb9..4f55779f473b 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
@@ -18,11 +18,16 @@ package com.android.server;
import android.annotation.NonNull;
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
import android.net.LinkAddress;
+import android.net.RouteInfo;
import android.os.Handler;
import android.os.RemoteException;
+import android.util.Log;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -32,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
* all INetworkManagementEventObserver objects that have registered with it.
*/
public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {
+ private static final String TAG = NetworkObserverRegistry.class.getSimpleName();
/**
* Constructs a new NetworkObserverRegistry.
@@ -50,7 +56,7 @@ public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub
netd.registerUnsolicitedEventListener(this);
}
- private final ConcurrentHashMap<NetworkObserver, Handler> mObservers =
+ private final ConcurrentHashMap<NetworkObserver, Optional<Handler>> mObservers =
new ConcurrentHashMap<>();
/**
@@ -58,7 +64,20 @@ public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub
* This method may be called on any thread.
*/
public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) {
- mObservers.put(observer, handler);
+ if (handler == null) {
+ throw new IllegalArgumentException("handler must be non-null");
+ }
+ mObservers.put(observer, Optional.of(handler));
+ }
+
+ /**
+ * Registers the specified observer, and start sending callbacks to it.
+ *
+ * <p>This method must only be called with callbacks that are nonblocking, such as callbacks
+ * that only send a message to a StateMachine.
+ */
+ public void registerObserverForNonblockingCallback(@NonNull NetworkObserver observer) {
+ mObservers.put(observer, Optional.empty());
}
/**
@@ -77,9 +96,19 @@ public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub
private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) {
// ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before
// creation will be processed, those added during traversal may or may not.
- for (Map.Entry<NetworkObserver, Handler> entry : mObservers.entrySet()) {
+ for (Map.Entry<NetworkObserver, Optional<Handler>> entry : mObservers.entrySet()) {
final NetworkObserver observer = entry.getKey();
- entry.getValue().post(() -> callback.sendCallback(observer));
+ final Optional<Handler> handler = entry.getValue();
+ if (handler.isPresent()) {
+ handler.get().post(() -> callback.sendCallback(observer));
+ return;
+ }
+
+ try {
+ callback.sendCallback(observer);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error sending callback to observer", e);
+ }
}
}
@@ -138,10 +167,13 @@ public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub
@Override
public void onRouteChanged(boolean updated, String route, String gateway, String ifName) {
+ final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
+ ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
+ ifName);
if (updated) {
- invokeForAllObservers(o -> o.onRouteUpdated(route, gateway, ifName));
+ invokeForAllObservers(o -> o.onRouteUpdated(processRoute));
} else {
- invokeForAllObservers(o -> o.onRouteRemoved(route, gateway, ifName));
+ invokeForAllObservers(o -> o.onRouteRemoved(processRoute));
}
}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 631ee453671a..7405c471808a 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -117,7 +117,11 @@ public class NetworkStackService extends Service {
mObserverRegistry = new NetworkObserverRegistry();
mCm = context.getSystemService(ConnectivityManager.class);
- // TODO: call mObserverRegistry here after adding sepolicy changes
+ try {
+ mObserverRegistry.register(mNetd);
+ } catch (RemoteException e) {
+ mLog.e("Error registering observer on Netd", e);
+ }
}
@NonNull
@@ -158,7 +162,7 @@ public class NetworkStackService extends Service {
@Override
public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
- final IpClient ipClient = new IpClient(mContext, ifName, cb);
+ final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
synchronized (mIpClients) {
final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 4ae044dec20b..7e57d1eb00b0 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -46,7 +46,6 @@ import android.net.RouteInfo;
import android.net.shared.InitialConfiguration;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
-import android.os.INetworkManagementService;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -54,7 +53,8 @@ import android.test.mock.MockContentResolver;
import com.android.internal.R;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.net.BaseNetworkObserver;
+import com.android.server.NetworkObserver;
+import com.android.server.NetworkObserverRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -87,15 +87,15 @@ public class IpClientTest {
@Mock private Context mContext;
@Mock private ConnectivityManager mCm;
- @Mock private INetworkManagementService mNMService;
+ @Mock private NetworkObserverRegistry mObserverRegistry;
@Mock private INetd mNetd;
@Mock private Resources mResources;
@Mock private IIpClientCallbacks mCb;
@Mock private AlarmManager mAlarm;
- @Mock private IpClient.Dependencies mDependecies;
+ @Mock private IpClient.Dependencies mDependencies;
private MockContentResolver mContentResolver;
- private BaseNetworkObserver mObserver;
+ private NetworkObserver mObserver;
private InterfaceParams mIfParams;
@Before
@@ -104,6 +104,7 @@ public class IpClientTest {
when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
+ when(mContext.getSystemService(INetd.class)).thenReturn(mNetd);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
.thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
@@ -113,28 +114,24 @@ public class IpClientTest {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mIfParams = null;
-
- when(mDependecies.getNMS()).thenReturn(mNMService);
- when(mDependecies.getNetd()).thenReturn(mNetd);
}
private void setTestInterfaceParams(String ifname) {
mIfParams = (ifname != null)
? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
: null;
- when(mDependecies.getInterfaceParams(anyString())).thenReturn(mIfParams);
+ when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
}
private IpClient makeIpClient(String ifname) throws Exception {
setTestInterfaceParams(ifname);
- final IpClient ipc = new IpClient(mContext, ifname, mCb, mDependecies);
+ final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
- ArgumentCaptor<BaseNetworkObserver> arg =
- ArgumentCaptor.forClass(BaseNetworkObserver.class);
- verify(mNMService, times(1)).registerObserver(arg.capture());
+ ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
+ verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture());
mObserver = arg.getValue();
- reset(mNMService);
+ reset(mObserverRegistry);
reset(mNetd);
// Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
verify(mCb, never()).onLinkPropertiesChange(any());
@@ -152,7 +149,8 @@ public class IpClientTest {
public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
setTestInterfaceParams(null);
try {
- final IpClient ipc = new IpClient(mContext, null, mCb, mDependecies);
+ final IpClient ipc = new IpClient(
+ mContext, null, mCb, mObserverRegistry, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -165,7 +163,8 @@ public class IpClientTest {
final String ifname = "lo";
setTestInterfaceParams(ifname);
try {
- final IpClient ipc = new IpClient(mContext, ifname, null, mDependecies);
+ final IpClient ipc = new IpClient(
+ mContext, ifname, null, mObserverRegistry, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -176,14 +175,16 @@ public class IpClientTest {
@Test
public void testInvalidInterfaceDoesNotThrow() throws Exception {
setTestInterfaceParams(TEST_IFNAME);
- final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+ final IpClient ipc = new IpClient(
+ mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
ipc.shutdown();
}
@Test
public void testInterfaceNotFoundFailsImmediately() throws Exception {
setTestInterfaceParams(null);
- final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+ final IpClient ipc = new IpClient(
+ mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
ipc.startProvisioning(new ProvisioningConfiguration());
verify(mCb, times(1)).onProvisioningFailure(any());
ipc.shutdown();
@@ -247,13 +248,13 @@ public class IpClientTest {
// Add N - 1 addresses
for (int i = 0; i < lastAddr; i++) {
- mObserver.addressUpdated(iface, new LinkAddress(addresses[i]));
+ mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface);
verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
reset(mCb);
}
// Add Nth address
- mObserver.addressUpdated(iface, new LinkAddress(addresses[lastAddr]));
+ mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
LinkProperties want = linkproperties(links(addresses), routes(prefixes));
want.setInterfaceName(iface);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a1aefabfc7f2..856b167b9175 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -707,17 +707,17 @@ class SettingsProtoDumpUtil {
Settings.Global.GPU_DEBUG_LAYERS_GLES,
GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES);
dumpSetting(s, p,
- Settings.Global.GUP_DEV_ALL_APPS,
- GlobalSettingsProto.Gpu.GUP_DEV_ALL_APPS);
+ Settings.Global.GAME_DRIVER_ALL_APPS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_ALL_APPS);
dumpSetting(s, p,
- Settings.Global.GUP_DEV_OPT_IN_APPS,
- GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS);
+ Settings.Global.GAME_DRIVER_OPT_IN_APPS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_IN_APPS);
dumpSetting(s, p,
- Settings.Global.GUP_DEV_OPT_OUT_APPS,
- GlobalSettingsProto.Gpu.GUP_DEV_OPT_OUT_APPS);
+ Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_OUT_APPS);
dumpSetting(s, p,
- Settings.Global.GUP_BLACKLIST,
- GlobalSettingsProto.Gpu.GUP_BLACKLIST);
+ Settings.Global.GAME_DRIVER_BLACKLIST,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLIST);
dumpSetting(s, p,
Settings.Global.GAME_DRIVER_WHITELIST,
GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 43e94352a902..385931d24bee 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6766,10 +6766,10 @@ message MetricsEvent {
// OS: Q
ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
- // OPEN: Settings > Developer Options > Game Update Packages
+ // OPEN: Settings > Developer Options > Game Driver Preferences
// CATEGORY: SETTINGS
// OS: Q
- SETTINGS_GUP_DASHBOARD = 1613;
+ SETTINGS_GAME_DRIVER_DASHBOARD = 1613;
// CATEGORY: The category for all actions relating to language detection logging.
// OS: Q
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 3d69aa8088f5..360d2960f61a 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -69,10 +69,11 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_ALL_APPS, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_OUT_APPS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACKLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_ALL_APPS, int.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_IN_APPS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 95665989cc34..7414e55ed94a 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -418,10 +418,15 @@ final class LogicalDisplay {
// Now add back the offset for the masked area.
mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
- mTempDisplayRect.left += mDisplayOffsetX;
- mTempDisplayRect.right += mDisplayOffsetX;
- mTempDisplayRect.top += mDisplayOffsetY;
- mTempDisplayRect.bottom += mDisplayOffsetY;
+ if (orientation == Surface.ROTATION_0) {
+ mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
+ } else if (orientation == Surface.ROTATION_90) {
+ mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
+ } else if (orientation == Surface.ROTATION_180) {
+ mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
+ } else { // Surface.ROTATION_270
+ mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
+ }
device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 863bfd5ea391..a8be07d76b58 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -480,6 +480,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
final String apkPath = pkg.baseCodePath;
final ApplicationInfo appInfo = pkg.applicationInfo;
final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+ if (appInfo.isPrivilegedApp()) {
+ // Privileged apps prefer to load trusted code so they don't use compiled views.
+ return false;
+ }
Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
") to " + outDexFile);
long callingId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
new file mode 100644
index 000000000000..fdcafa77a378
--- /dev/null
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.Handler;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.DisplayInfo;
+import android.view.IDisplayFoldListener;
+
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
+
+/**
+ * Controls the behavior of foldable devices whose screen can literally bend and fold.
+ */
+class DisplayFoldController {
+
+ private static final String TAG = "DisplayFoldController";
+ private final WindowManagerInternal mWindowManagerInternal;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+ private final int mDisplayId;
+
+ /** The display area while device is folded. */
+ private final Rect mFoldedArea;
+ private final Handler mHandler;
+
+ private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo();
+ private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>();
+ private Boolean mFolded;
+
+ DisplayFoldController(WindowManagerInternal windowManagerInternal,
+ DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea,
+ Handler handler) {
+ mWindowManagerInternal = windowManagerInternal;
+ mDisplayManagerInternal = displayManagerInternal;
+ mDisplayId = displayId;
+ mFoldedArea = new Rect(foldedArea);
+ mHandler = handler;
+ }
+
+ void requestDeviceFolded(boolean folded) {
+ mHandler.post(() -> setDeviceFolded(folded));
+ }
+
+ void setDeviceFolded(boolean folded) {
+ if (mFolded != null && mFolded == folded) {
+ return;
+ }
+ if (folded) {
+ mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mNonOverrideDisplayInfo);
+ final int dx = (mNonOverrideDisplayInfo.logicalWidth - mFoldedArea.width()) / 2
+ - mFoldedArea.left;
+ final int dy = (mNonOverrideDisplayInfo.logicalHeight - mFoldedArea.height()) / 2
+ - mFoldedArea.top;
+
+ mWindowManagerInternal.setForcedDisplaySize(mDisplayId, mFoldedArea.width(),
+ mFoldedArea.height());
+ mDisplayManagerInternal.setDisplayOffsets(mDisplayId, -dx, -dy);
+ } else {
+ mWindowManagerInternal.clearForcedDisplaySize(mDisplayId);
+ mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0);
+ }
+ mFolded = folded;
+
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mListeners.getBroadcastItem(i).onDisplayFoldChanged(mDisplayId, folded);
+ } catch (RemoteException e) {
+ // Listener died.
+ }
+ }
+ mListeners.finishBroadcast();
+ }
+
+ void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ mListeners.register(listener);
+ if (mFolded == null) {
+ return;
+ }
+ mHandler.post(() -> {
+ try {
+ listener.onDisplayFoldChanged(mDisplayId, mFolded);
+ } catch (RemoteException e) {
+ // Listener died.
+ }
+ });
+ }
+
+ void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ mListeners.unregister(listener);
+ }
+
+ /**
+ * Only used for the case that persist.debug.force_foldable is set.
+ * This is using proximity sensor to simulate the fold state switch.
+ */
+ static DisplayFoldController createWithProxSensor(Context context, int displayId) {
+ final SensorManager sensorManager = context.getSystemService(SensorManager.class);
+ final Sensor proxSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ if (proxSensor == null) {
+ return null;
+ }
+
+ final DisplayFoldController result = create(displayId);
+ sensorManager.registerListener(new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ result.requestDeviceFolded(event.values[0] < 1f);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Ignore.
+ }
+ }, proxSensor, SensorManager.SENSOR_DELAY_NORMAL);
+
+ return result;
+ }
+
+ static DisplayFoldController create(int displayId) {
+ final DisplayManagerInternal displayService =
+ LocalServices.getService(DisplayManagerInternal.class);
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayService.getNonOverrideDisplayInfo(displayId, displayInfo);
+ final Rect foldedArea = new Rect(0, displayInfo.logicalHeight / 2,
+ displayInfo.logicalWidth, displayInfo.logicalHeight);
+
+ return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class),
+ displayService, displayId, foldedArea, DisplayThread.getHandler());
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 13c4d886e7b1..0796a9c896a3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -177,6 +177,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.HapticFeedbackConstants;
+import android.view.IDisplayFoldListener;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -374,6 +375,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
SearchManager mSearchManager;
AccessibilityManager mAccessibilityManager;
BurnInProtectionHelper mBurnInProtectionHelper;
+ private DisplayFoldController mDisplayFoldController;
AppOpsManager mAppOpsManager;
private ScreenshotHelper mScreenshotHelper;
private boolean mHasFeatureWatch;
@@ -471,6 +473,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mLidNavigationAccessibility;
boolean mLidControlsScreenLock;
boolean mLidControlsSleep;
+ private boolean mLidControlsDisplayFold;
int mShortPressOnPowerBehavior;
int mLongPressOnPowerBehavior;
int mVeryLongPressOnPowerBehavior;
@@ -1794,6 +1797,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.bool.config_lidControlsScreenLock);
mLidControlsSleep = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_lidControlsSleep);
+ mLidControlsDisplayFold = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_lidControlsDisplayFold);
mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
@@ -1850,6 +1855,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
readConfigurationDependentBehaviors();
+ if (mLidControlsDisplayFold) {
+ mDisplayFoldController = DisplayFoldController.create(DEFAULT_DISPLAY);
+ } else if (SystemProperties.getBoolean("persist.debug.force_foldable", false)) {
+ mDisplayFoldController = DisplayFoldController.createWithProxSensor(context,
+ DEFAULT_DISPLAY);
+ }
+
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
@@ -3194,6 +3206,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
+ public void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.registerDisplayFoldListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.unregisterDisplayFoldListener(listener);
+ }
+ }
+
+ @Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
throws RemoteException {
synchronized (mLock) {
@@ -4972,7 +4998,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void applyLidSwitchState() {
final int lidState = mDefaultDisplayPolicy.getLidState();
- if (lidState == LID_CLOSED && mLidControlsSleep) {
+ if (mLidControlsDisplayFold && mDisplayFoldController != null) {
+ mDisplayFoldController.requestDeviceFolded(lidState == LID_CLOSED);
+ } else if (lidState == LID_CLOSED && mLidControlsSleep) {
goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
} else if (lidState == LID_CLOSED && mLidControlsScreenLock) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 1d829707f180..e18cd179b113 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -78,6 +78,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.IApplicationToken;
+import android.view.IDisplayFoldListener;
import android.view.IWindowManager;
import android.view.InputEventReceiver;
import android.view.KeyEvent;
@@ -1457,6 +1458,16 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public void requestUserActivityNotification();
/**
+ * Registers an IDisplayFoldListener.
+ */
+ default void registerDisplayFoldListener(IDisplayFoldListener listener) {}
+
+ /**
+ * Unregisters an IDisplayFoldListener.
+ */
+ default void unregisterDisplayFoldListener(IDisplayFoldListener listener) {}
+
+ /**
* Updates the flag about whether AOD is showing.
*
* @return whether the value was changed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index e204697e46cf..33e46f4af301 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -313,6 +313,22 @@ public abstract class WindowManagerInternal {
public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout);
/**
+ * Overrides the display size.
+ *
+ * @param displayId The display to override the display size.
+ * @param width The width to override.
+ * @param height The height to override.
+ */
+ public abstract void setForcedDisplaySize(int displayId, int width, int height);
+
+ /**
+ * Recover the display size to real display size.
+ *
+ * @param displayId The display to recover the display size.
+ */
+ public abstract void clearForcedDisplaySize(int displayId);
+
+ /**
* Adds a window token for a given window type.
*
* @param token The token to add.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e6581df233ef..8373b44112fe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -192,6 +192,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.IDisplayFoldListener;
import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
@@ -3748,6 +3749,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void registerDisplayFoldListener(IDisplayFoldListener listener) {
+ mPolicy.registerDisplayFoldListener(listener);
+ }
+
+ @Override
+ public void unregisterDisplayFoldListener(IDisplayFoldListener listener) {
+ mPolicy.unregisterDisplayFoldListener(listener);
+ }
+
+ @Override
public int getPreferredOptionsPanelGravity(int displayId) {
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -6937,6 +6948,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void setForcedDisplaySize(int displayId, int width, int height) {
+ WindowManagerService.this.setForcedDisplaySize(displayId, width, height);
+ }
+
+ @Override
+ public void clearForcedDisplaySize(int displayId) {
+ WindowManagerService.this.clearForcedDisplaySize(displayId);
+ }
+
+ @Override
public void addWindowToken(IBinder token, int type, int displayId) {
WindowManagerService.this.addWindowToken(token, type, displayId);
}
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
index ea3f758fb209..98bad93e09e2 100644
--- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -170,4 +170,9 @@ public class WmDisplayCutout {
public int hashCode() {
return Objects.hash(mInner, mFrameSize);
}
+
+ @Override
+ public String toString() {
+ return "WmDisplayCutout{" + mInner + ", mFrameSize=" + mFrameSize + '}';
+ }
}
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
index 3921cfbbfce7..7250eee70ecb 100644
--- a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
+++ b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
@@ -64,6 +64,10 @@ public class StatusCode implements Parcelable {
public static final int UCE_NO_CHANGE_IN_CAP = 13;
/** Service is unknown. */
public static final int UCE_SERVICE_UNKNOWN = 14;
+ /** Service cannot support Invalid Feature Tag */
+ public static final int UCE_INVALID_FEATURE_TAG = 15;
+ /** Service is Available */
+ public static final int UCE_SERVICE_AVAILABLE = 16;
private int mStatusCode = UCE_SUCCESS;
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
index 43f83cd94d57..1fb8513d410a 100644
--- a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
@@ -66,10 +66,30 @@ interface IUceService
* service the client created.
*
* @return optionsServiceHandle
+ *
* @hide
+ *
+ * @deprecated This is replaced with new API createOptionsServiceForSubscription()
*/
int createOptionsService(IOptionsListener optionsListener,
inout UceLong optionsServiceListenerHdl);
+ /**
+ * Creates a options service for Capability Discovery.
+ * @param optionsListener IOptionsListener object.
+ * @param optionsServiceListenerHdl wrapper for client's listener handle to be stored.
+ * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+ *
+ * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+ * used to validate callbacks received in IPresenceListener are indeed from the
+ * service the client created.
+ *
+ * @return optionsServiceHandle
+ *
+ * @hide
+ */
+ int createOptionsServiceForSubscription(IOptionsListener optionsListener,
+ inout UceLong optionsServiceListenerHdl,
+ in String iccId);
/**
* Destroys a Options service.
@@ -89,14 +109,36 @@ interface IUceService
* service the client created.
*
* @return presenceServiceHdl
+ *
* @hide
+ *
+ * @deprecated This is replaced with new API createPresenceServiceForSubscription()
*/
int createPresenceService(IPresenceListener presenceServiceListener,
inout UceLong presenceServiceListenerHdl);
+ /**
+ * Creates a presence service.
+ * @param presenceServiceListener IPresenceListener object
+ * @param presenceServiceListenerHdl wrapper for client's listener handle to be stored.
+ * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+ *
+ * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+ * used to validate callbacks received in IPresenceListener are indeed from the
+ * service the client created.
+ *
+ * @return presenceServiceHdl
+ *
+ * @hide
+ */
+ int createPresenceServiceForSubscription(IPresenceListener presenceServiceListener,
+ inout UceLong presenceServiceListenerHdl,
+ in String iccId);
/**
* Destroys a presence service.
+ *
* @param presenceServiceHdl handle returned during createPresenceService()
+ *
* @hide
*/
void destroyPresenceService(int presenceServiceHdl);
@@ -105,23 +147,55 @@ interface IUceService
/**
* Query the UCE Service for information to know whether the is registered.
+ *
* @return boolean, true if Registered to for network events else false.
+ *
* @hide
*/
boolean getServiceStatus();
/**
* Query the UCE Service for presence Service.
+ *
* @return IPresenceService object.
+ *
* @hide
+ *
+ * @deprecated use API getPresenceServiceForSubscription()
*/
IPresenceService getPresenceService();
/**
+ * Query the UCE Service for presence Service.
+ *
+ * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+ *
+ * @return IPresenceService object.
+ *
+ * @hide
+ */
+ IPresenceService getPresenceServiceForSubscription(in String iccId);
+
+ /**
* Query the UCE Service for options service object.
+ *
* @return IOptionsService object.
+ *
+ * @deprecated use API getOptionsServiceForSubscription()
+ *
* @hide
*/
IOptionsService getOptionsService();
+ /**
+ * Query the UCE Service for options service object.
+ *
+ * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+ *
+ * @return IOptionsService object.
+ *
+ * @hide
+ */
+ IOptionsService getOptionsServiceForSubscription(in String iccId);
+
}
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
index 3660e039582d..ceb191910427 100644
--- a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
@@ -56,6 +56,14 @@ public abstract class UceServiceBase {
return onCreateOptionsService(optionsListener, optionsServiceListenerHdl);
}
+ @Override
+ public int createOptionsServiceForSubscription(IOptionsListener optionsListener,
+ UceLong optionsServiceListenerHdl,
+ String iccId) {
+ return onCreateOptionsService(optionsListener, optionsServiceListenerHdl,
+ iccId);
+ }
+
@Override
public void destroyOptionsService(int optionsServiceHandle) {
@@ -70,6 +78,14 @@ public abstract class UceServiceBase {
}
@Override
+ public int createPresenceServiceForSubscription(IPresenceListener presServiceListener,
+ UceLong presServiceListenerHdl,
+ String iccId) {
+ return onCreatePresService(presServiceListener, presServiceListenerHdl,
+ iccId);
+ }
+
+ @Override
public void destroyPresenceService(int presServiceHdl) {
onDestroyPresService(presServiceHdl);
}
@@ -85,9 +101,19 @@ public abstract class UceServiceBase {
}
@Override
+ public IPresenceService getPresenceServiceForSubscription(String iccId) {
+ return onGetPresenceService(iccId);
+ }
+
+ @Override
public IOptionsService getOptionsService() {
return onGetOptionsService();
}
+
+ @Override
+ public IOptionsService getOptionsServiceForSubscription(String iccId) {
+ return onGetOptionsService(iccId);
+ }
}
private UceServiceBinder mBinder;
@@ -120,6 +146,13 @@ public abstract class UceServiceBase {
return 0;
}
+ protected int onCreateOptionsService(IOptionsListener optionsListener,
+ UceLong optionsServiceListenerHdl,
+ String iccId) {
+ //no-op
+ return 0;
+ }
+
protected void onDestroyOptionsService(int cdServiceHandle) {
//no-op
return;
@@ -131,6 +164,13 @@ public abstract class UceServiceBase {
return 0;
}
+ protected int onCreatePresService(IPresenceListener presServiceListener,
+ UceLong presServiceListenerHdl,
+ String iccId) {
+ //no-op
+ return 0;
+ }
+
protected void onDestroyPresService(int presServiceHdl) {
//no-op
return;
@@ -146,8 +186,18 @@ public abstract class UceServiceBase {
return null;
}
+ protected IPresenceService onGetPresenceService(String iccId) {
+ //no-op
+ return null;
+ }
+
protected IOptionsService onGetOptionsService () {
//no-op
return null;
}
+
+ protected IOptionsService onGetOptionsService (String iccId) {
+ //no-op
+ return null;
+ }
}