Merge changes from topic "netutils_split"
* changes:
Add DeviceConfigUtils version caching and tests
Add getDisplayTransport
Split NetworkStackUtils to frameworks/libs/net
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 8943453..6567c5e 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -49,6 +49,8 @@
"//frameworks/opt/net/ike",
"//frameworks/opt/net/wifi/service",
"//frameworks/opt/net/telephony",
+ "//frameworks/base/packages/Connectivity:__subpackages__",
+ "//packages/modules/Connectivity:__subpackages__",
"//packages/modules/NetworkStack:__subpackages__",
"//packages/modules/CaptivePortalLogin",
"//frameworks/libs/net/common/tests:__subpackages__",
@@ -133,9 +135,12 @@
"//frameworks/opt/net/ike",
"//frameworks/opt/telephony",
"//frameworks/base/wifi:__subpackages__",
+ "//frameworks/base/packages/Connectivity:__subpackages__",
+ "//packages/modules/Connectivity:__subpackages__",
"//packages/modules/NetworkStack:__subpackages__",
"//packages/modules/CaptivePortalLogin",
"//frameworks/libs/net/common/tests:__subpackages__",
+ "//packages/modules/Wifi/framework/tests:__subpackages__",
]
}
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
index 1572fe0..a227505 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkStackConstants.java
@@ -46,6 +46,12 @@
public static final int ETHER_TYPE_IPV6 = 0x86dd;
public static final int ETHER_HEADER_LEN = 14;
public static final int ETHER_MTU = 1500;
+ public static final byte[] ETHER_BROADCAST = new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ };
+
+ public static final int DEFAULT_LINK_MTU = 1500;
/**
* ARP constants.
diff --git a/staticlibs/framework/com/android/net/module/util/ProxyUtils.java b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java
new file mode 100644
index 0000000..a7b8393
--- /dev/null
+++ b/staticlibs/framework/com/android/net/module/util/ProxyUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.net.module.util;
+
+import android.text.TextUtils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Collection of network common utilities.
+ *
+ * @hide
+ */
+public final class ProxyUtils {
+
+ /** Converts exclusion list from String to List. */
+ public static List<String> exclusionStringAsList(String exclusionList) {
+ if (exclusionList == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(exclusionList.toLowerCase(Locale.ROOT).split(","));
+ }
+
+ /** Converts exclusion list from List to string */
+ public static String exclusionListAsString(String[] exclusionList) {
+ if (exclusionList == null) {
+ return "";
+ }
+ return TextUtils.join(",", exclusionList);
+ }
+}
diff --git a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt
index b647d99..efd77d1 100644
--- a/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt
+++ b/staticlibs/hostdevice/com/android/net/module/util/TrackRecord.kt
@@ -19,6 +19,7 @@
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
+import java.util.concurrent.locks.StampedLock
import kotlin.concurrent.withLock
/**
@@ -137,12 +138,6 @@
* instance can also be used concurrently. ReadHead maintains the current index that is
* the next to be read, and calls this the "mark".
*
- * A ReadHead delegates all TrackRecord methods to its associated ArrayTrackRecord, and
- * inherits its thread-safe properties. However, the additional methods that ReadHead
- * offers on top of TrackRecord do not share these properties and can only be used by
- * the thread that created the ReadHead. This is because by construction it does not
- * make sense to use a ReadHead on multiple threads concurrently (see below for details).
- *
* In a ReadHead, {@link poll(Long, (E) -> Boolean)} works similarly to a LinkedBlockingQueue.
* It can be called repeatedly and will return the elements as they arrive.
*
@@ -162,21 +157,43 @@
* The point is that the caller does not have to track the mark like it would have to if
* it was using ArrayTrackRecord directly.
*
- * Note that if multiple threads were using poll() concurrently on the same ReadHead, what
- * happens to the mark and the return values could be well defined, but it could not
- * be useful because there is no way to provide either a guarantee not to skip objects nor
- * a guarantee about the mark position at the exit of poll(). This is even more true in the
- * presence of a predicate to filter returned elements, because one thread might be
- * filtering out the events the other is interested in.
- * Instead, this use case is supported by creating multiple ReadHeads on the same instance
- * of ArrayTrackRecord. Each ReadHead is then guaranteed to see all events always and
- * guarantees are made on the value of the mark upon return. {@see poll(Long, (E) -> Boolean)}
- * for details. Be careful to create each ReadHead on the thread it is meant to be used on.
+ * Thread safety :
+ * A ReadHead delegates all TrackRecord methods to its associated ArrayTrackRecord, and
+ * inherits its thread-safe properties for all the TrackRecord methods.
*
- * Users of a ReadHead can ask for the current position of the mark at any time. This mark
- * can be used later to replay the history of events either on this ReadHead, on the associated
- * ArrayTrackRecord or on another ReadHead associated with the same ArrayTrackRecord. It
- * might look like this in the reader thread :
+ * Poll() operates under its own set of rules that only allow execution on multiple threads
+ * within constrained boundaries, and never concurrently or pseudo-concurrently. This is
+ * because concurrent calls to poll() fundamentally do not make sense. poll() will move
+ * the mark according to what events remained to be read by this read head, and therefore
+ * if multiple threads were calling poll() concurrently on the same ReadHead, what
+ * happens to the mark and the return values could not be useful because there is no way to
+ * provide either a guarantee not to skip objects nor a guarantee about the mark position at
+ * the exit of poll(). This is even more true in the presence of a predicate to filter
+ * returned elements, because one thread might be filtering out the events the other is
+ * interested in. For this reason, this class will fail-fast if any concurrent access is
+ * detected with ConcurrentAccessException.
+ * It is possible to use poll() on different threads as long as the following can be
+ * guaranteed : one thread must call poll() for the last time, then execute a write barrier,
+ * then the other thread must execute a read barrier before calling poll() for the first time.
+ * This allows in particular to call poll in @Before and @After methods in JUnit unit tests,
+ * because JUnit will enforce those barriers by creating the testing thread after executing
+ * @Before and joining the thread after executing @After.
+ *
+ * peek() can be used by multiple threads concurrently, but only if no thread is calling
+ * poll() outside of the boundaries above. For simplicity, it can be considered that peek()
+ * is safe to call only when poll() is safe to call.
+ *
+ * Polling concurrently from the same ArrayTrackRecord is supported by creating multiple
+ * ReadHeads on the same instance of ArrayTrackRecord (or of course by using ArrayTrackRecord
+ * directly). Each ReadHead is then guaranteed to see all events always and
+ * guarantees are made on the value of the mark upon return. {@see poll(Long, (E) -> Boolean)}
+ * for details. Be careful to create each ReadHead on the thread it is meant to be used on, or
+ * to have a clear synchronization point between creation and use.
+ *
+ * Users of a ReadHead can ask for the current position of the mark at any time, on a thread
+ * where it's safe to call peek(). This mark can be used later to replay the history of events
+ * either on this ReadHead, on the associated ArrayTrackRecord or on another ReadHead
+ * associated with the same ArrayTrackRecord. It might look like this in the reader thread :
*
* val markAtStart = record.mark
* // Start processing interesting events
@@ -190,22 +207,39 @@
* val specialElement = record.poll(timeout, markAtStart) { it.isSpecial() }
*/
inner class ReadHead : TrackRecord<E> by this@ArrayTrackRecord {
- private val owningThread = Thread.currentThread()
+ // This lock only controls access to the readHead member below. The ArrayTrackRecord
+ // object has its own synchronization following different (and more usual) semantics.
+ // See the comment on the ReadHead class for details.
+ private val slock = StampedLock()
private var readHead = 0
/**
* @return the current value of the mark.
*/
var mark
- get() = readHead.also { checkThread() }
+ get() = checkThread { readHead }
set(v: Int) = rewind(v)
fun rewind(v: Int) {
- checkThread()
+ val stamp = slock.tryWriteLock()
+ if (0L == stamp) concurrentAccessDetected()
readHead = v
+ slock.unlockWrite(stamp)
}
- private fun checkThread() = check(Thread.currentThread() == owningThread) {
- "Must be called by the thread that created this object"
+ private fun <T> checkThread(r: (Long) -> T): T {
+ // tryOptimisticRead is a read barrier, guarantees writes from other threads are visible
+ // after it
+ val stamp = slock.tryOptimisticRead()
+ val result = r(stamp)
+ // validate also performs a read barrier, guaranteeing that if validate returns true,
+ // then any change either happens-before tryOptimisticRead, or happens-after validate.
+ if (!slock.validate(stamp)) concurrentAccessDetected()
+ return result
+ }
+
+ private fun concurrentAccessDetected(): Nothing {
+ throw ConcurrentModificationException(
+ "ReadHeads can't be used concurrently. Check your threading model.")
}
/**
@@ -225,21 +259,27 @@
* @return an element matching the predicate, or null if timeout.
*/
fun poll(timeoutMs: Long, predicate: (E) -> Boolean = { true }): E? {
- checkThread()
- lock.withLock {
- val index = pollForIndexReadLocked(timeoutMs, readHead, predicate)
- readHead = if (index < 0) size else index + 1
- return getOrNull(index)
+ val stamp = slock.tryWriteLock()
+ if (0L == stamp) concurrentAccessDetected()
+ try {
+ lock.withLock {
+ val index = pollForIndexReadLocked(timeoutMs, readHead, predicate)
+ readHead = if (index < 0) size else index + 1
+ return getOrNull(index)
+ }
+ } finally {
+ slock.unlockWrite(stamp)
}
}
/**
* Returns the first element after the mark or null. This never blocks.
*
- * This method can only be used by the thread that created this ManagedRecordingQueue.
- * If used on another thread, this throws IllegalStateException.
+ * This method is subject to threading restrictions. It can be used concurrently on
+ * multiple threads but not if any other thread might be executing poll() at the same
+ * time. See the class comment for details.
*/
- fun peek(): E? = getOrNull(readHead).also { checkThread() }
+ fun peek(): E? = checkThread { getOrNull(readHead) }
}
}