Merge "KernelWakelockReader: reuse buffer when parsing"
diff --git a/Android.bp b/Android.bp
index 05675df..8f5675f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -925,6 +925,7 @@
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
"test-mock/src/**/*.java",
@@ -988,6 +989,7 @@
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
+ ":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
],
diff --git a/api/current.txt b/api/current.txt
index 436ebdc..35e2acaf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28695,6 +28695,7 @@
method @Nullable public String getPrivateDnsServerName();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
method public boolean isPrivateDnsActive();
+ method public boolean isWakeOnLanSupported();
method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setDomains(@Nullable String);
method public void setHttpProxy(@Nullable android.net.ProxyInfo);
@@ -47777,6 +47778,7 @@
ctor public ArraySet(int);
ctor public ArraySet(android.util.ArraySet<E>);
ctor public ArraySet(java.util.Collection<? extends E>);
+ ctor public ArraySet(@Nullable E[]);
method public boolean add(E);
method public void addAll(android.util.ArraySet<? extends E>);
method public boolean addAll(java.util.Collection<? extends E>);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d780b09b..4450ff2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1157,6 +1157,10 @@
sendMessage(H.ATTACH_AGENT, agent);
}
+ public void attachStartupAgents(String dataDir) {
+ sendMessage(H.ATTACH_STARTUP_AGENTS, dataDir);
+ }
+
public void setSchedulingGroup(int group) {
// Note: do this immediately, since going into the foreground
// should happen regardless of what pending work we have to do
@@ -1806,6 +1810,7 @@
public static final int EXECUTE_TRANSACTION = 159;
public static final int RELAUNCH_ACTIVITY = 160;
public static final int PURGE_RESOURCES = 161;
+ public static final int ATTACH_STARTUP_AGENTS = 162;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1849,6 +1854,7 @@
case EXECUTE_TRANSACTION: return "EXECUTE_TRANSACTION";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PURGE_RESOURCES: return "PURGE_RESOURCES";
+ case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
}
}
return Integer.toString(code);
@@ -2031,6 +2037,9 @@
case PURGE_RESOURCES:
schedulePurgeIdler();
break;
+ case ATTACH_STARTUP_AGENTS:
+ handleAttachStartupAgents((String) msg.obj);
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -3729,6 +3738,27 @@
}
}
+ static void handleAttachStartupAgents(String dataDir) {
+ try {
+ Path code_cache = ContextImpl.getCodeCacheDirBeforeBind(new File(dataDir)).toPath();
+ if (!Files.exists(code_cache)) {
+ return;
+ }
+ Path startup_path = code_cache.resolve("startup_agents");
+ if (Files.exists(startup_path)) {
+ for (Path p : Files.newDirectoryStream(startup_path)) {
+ handleAttachAgent(
+ p.toAbsolutePath().toString()
+ + "="
+ + dataDir,
+ null);
+ }
+ }
+ } catch (Exception e) {
+ // Ignored.
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
@@ -6366,26 +6396,6 @@
NetworkSecurityConfigProvider.install(appContext);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- if (isAppDebuggable) {
- try {
- // Load all the agents in the code_cache/startup_agents directory.
- // We pass the absolute path to the data_dir as an argument.
- Path startup_path = appContext.getCodeCacheDir().toPath().resolve("startup_agents");
- if (Files.exists(startup_path)) {
- for (Path p : Files.newDirectoryStream(startup_path)) {
- handleAttachAgent(
- p.toAbsolutePath().toString()
- + "="
- + appContext.getDataDir().toPath().toAbsolutePath().toString(),
- data.info);
- }
- }
- } catch (Exception e) {
- // Ignored.
- }
- }
-
// Continue loading instrumentation.
if (ii != null) {
ApplicationInfo instrApp;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 41a4fba..b915473 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -739,12 +739,21 @@
public File getCodeCacheDir() {
synchronized (mSync) {
if (mCodeCacheDir == null) {
- mCodeCacheDir = new File(getDataDir(), "code_cache");
+ mCodeCacheDir = getCodeCacheDirBeforeBind(getDataDir());
}
return ensurePrivateCacheDirExists(mCodeCacheDir, XATTR_INODE_CODE_CACHE);
}
}
+ /**
+ * Helper for getting code-cache dir potentially before application bind.
+ *
+ * @hide
+ */
+ static File getCodeCacheDirBeforeBind(File dataDir) {
+ return new File(dataDir, "code_cache");
+ }
+
@Override
public File getExternalCacheDir() {
// Operates on primary external storage
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index cfa065b..51a64ff 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -137,6 +137,7 @@
IVoiceInteractor voiceInteractor);
void handleTrustStorageUpdate();
void attachAgent(String path);
+ void attachStartupAgents(String dataDir);
void scheduleApplicationInfoChanged(in ApplicationInfo ai);
void setNetworkBlockSeq(long procStateSeq);
void scheduleTransaction(in ClientTransaction transaction);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index d3f48ac..3ec0aea 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -68,6 +68,7 @@
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
private String mTcpBufferSizes;
private IpPrefix mNat64Prefix;
+ private boolean mWakeOnLanSupported;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -193,6 +194,7 @@
setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
mNat64Prefix = source.mNat64Prefix;
+ mWakeOnLanSupported = source.mWakeOnLanSupported;
}
}
@@ -852,6 +854,7 @@
mMtu = 0;
mTcpBufferSizes = null;
mNat64Prefix = null;
+ mWakeOnLanSupported = false;
}
/**
@@ -913,6 +916,10 @@
resultJoiner.add("MTU:");
resultJoiner.add(Integer.toString(mMtu));
+ if (mWakeOnLanSupported) {
+ resultJoiner.add("WakeOnLanSupported: true");
+ }
+
if (mTcpBufferSizes != null) {
resultJoiner.add("TcpBufferSizes:");
resultJoiner.add(mTcpBufferSizes);
@@ -1425,6 +1432,37 @@
}
/**
+ * Compares this {@code LinkProperties} WakeOnLan supported against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalWakeOnLan(LinkProperties target) {
+ return isWakeOnLanSupported() == target.isWakeOnLanSupported();
+ }
+
+ /**
+ * Set whether the network interface supports WakeOnLAN
+ *
+ * @param supported WakeOnLAN supported value
+ *
+ * @hide
+ */
+ public void setWakeOnLanSupported(boolean supported) {
+ mWakeOnLanSupported = supported;
+ }
+
+ /**
+ * Returns whether the network interface supports WakeOnLAN
+ *
+ * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
+ */
+ public boolean isWakeOnLanSupported() {
+ return mWakeOnLanSupported;
+ }
+
+ /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
@@ -1461,7 +1499,8 @@
&& isIdenticalStackedLinks(target)
&& isIdenticalMtu(target)
&& isIdenticalTcpBufferSizes(target)
- && isIdenticalNat64Prefix(target);
+ && isIdenticalNat64Prefix(target)
+ && isIdenticalWakeOnLan(target);
}
/**
@@ -1577,7 +1616,8 @@
+ (mUsePrivateDns ? 57 : 0)
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
- + Objects.hash(mNat64Prefix);
+ + Objects.hash(mNat64Prefix)
+ + (mWakeOnLanSupported ? 71 : 0);
}
/**
@@ -1622,6 +1662,8 @@
ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
dest.writeList(stackedLinks);
+
+ dest.writeBoolean(mWakeOnLanSupported);
}
/**
@@ -1677,6 +1719,7 @@
for (LinkProperties stackedLink: stackedLinks) {
netProp.addStackedLink(stackedLink);
}
+ netProp.setWakeOnLanSupported(in.readBoolean());
return netProp;
}
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index cfb582e..5e8929c 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -23,6 +23,8 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import dalvik.annotation.optimization.FastNative;
+
import libcore.util.NativeAllocationRegistry;
import java.lang.annotation.Retention;
@@ -72,46 +74,54 @@
/**
* Writes an interface token into the parcel used to verify that
- * a transaction has made it to the write type of interface.
+ * a transaction has made it to the right type of interface.
*
* @param interfaceName fully qualified name of interface message
* is being sent to.
*/
+ @FastNative
public native final void writeInterfaceToken(String interfaceName);
/**
* Writes a boolean value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeBool(boolean val);
/**
* Writes a byte value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt8(byte val);
/**
* Writes a short value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt16(short val);
/**
* Writes a int value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt32(int val);
/**
* Writes a long value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeInt64(long val);
/**
* Writes a float value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeFloat(float val);
/**
* Writes a double value to the end of the parcel.
* @param val to write
*/
+ @FastNative
public native final void writeDouble(double val);
/**
* Writes a String value to the end of the parcel.
@@ -120,6 +130,7 @@
*
* @param val to write
*/
+ @FastNative
public native final void writeString(String val);
/**
* Writes a native handle (without duplicating the underlying
@@ -127,42 +138,50 @@
*
* @param val to write
*/
+ @FastNative
public native final void writeNativeHandle(@Nullable NativeHandle val);
/**
* Writes an array of boolean values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeBoolVector(boolean[] val);
/**
* Writes an array of byte values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt8Vector(byte[] val);
/**
* Writes an array of short values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt16Vector(short[] val);
/**
* Writes an array of int values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt32Vector(int[] val);
/**
* Writes an array of long values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeInt64Vector(long[] val);
/**
* Writes an array of float values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeFloatVector(float[] val);
/**
* Writes an array of double values to the end of the parcel.
* @param val to write
*/
+ @FastNative
private native final void writeDoubleVector(double[] val);
/**
* Writes an array of String values to the end of the parcel.
@@ -171,6 +190,7 @@
*
* @param val to write
*/
+ @FastNative
private native final void writeStringVector(String[] val);
/**
* Writes an array of native handles to the end of the parcel.
@@ -179,6 +199,7 @@
*
* @param val array of {@link NativeHandle} objects to write
*/
+ @FastNative
private native final void writeNativeHandleVector(NativeHandle[] val);
/**
@@ -299,6 +320,7 @@
* Write a hwbinder object to the end of the parcel.
* @param binder value to write
*/
+ @FastNative
public native final void writeStrongBinder(IHwBinder binder);
/**
@@ -314,48 +336,56 @@
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final boolean readBool();
/**
* Reads a byte value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final byte readInt8();
/**
* Reads a short value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final short readInt16();
/**
* Reads a int value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final int readInt32();
/**
* Reads a long value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final long readInt64();
/**
* Reads a float value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final float readFloat();
/**
* Reads a double value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final double readDouble();
/**
* Reads a String value from the current location in the parcel.
* @return value parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final String readString();
/**
* Reads a native handle (without duplicating the underlying file
@@ -366,6 +396,7 @@
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readNativeHandle();
/**
* Reads an embedded native handle (without duplicating the underlying
@@ -379,6 +410,7 @@
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final @Nullable NativeHandle readEmbeddedNativeHandle(
long parentHandle, long offset);
@@ -387,54 +419,63 @@
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final boolean[] readBoolVectorAsArray();
/**
* Reads an array of byte values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final byte[] readInt8VectorAsArray();
/**
* Reads an array of short values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final short[] readInt16VectorAsArray();
/**
* Reads an array of int values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final int[] readInt32VectorAsArray();
/**
* Reads an array of long values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final long[] readInt64VectorAsArray();
/**
* Reads an array of float values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final float[] readFloatVectorAsArray();
/**
* Reads an array of double values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final double[] readDoubleVectorAsArray();
/**
* Reads an array of String values from the parcel.
* @return array of parsed values
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final String[] readStringVectorAsArray();
/**
* Reads an array of native handles from the parcel.
* @return array of {@link NativeHandle} objects
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
private native final NativeHandle[] readNativeHandleAsArray();
/**
@@ -537,6 +578,7 @@
* @return binder object read from parcel or null if no binder can be read
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final IHwBinder readStrongBinder();
/**
@@ -544,6 +586,7 @@
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
*/
+ @FastNative
public native final HwBlob readBuffer(long expectedSize);
/**
@@ -559,6 +602,7 @@
* @throws NullPointerException if the transaction specified the blob to be null
* but nullable is false
*/
+ @FastNative
public native final HwBlob readEmbeddedBuffer(
long expectedSize, long parentHandle, long offset,
boolean nullable);
@@ -567,26 +611,31 @@
* Write a buffer into the transaction.
* @param blob blob to write into the parcel.
*/
+ @FastNative
public native final void writeBuffer(HwBlob blob);
/**
* Write a status value into the blob.
* @param status value to write
*/
+ @FastNative
public native final void writeStatus(int status);
/**
* @throws IllegalArgumentException if a success vaue cannot be read
* @throws RemoteException if success value indicates a transaction error
*/
+ @FastNative
public native final void verifySuccess();
/**
* Should be called to reduce memory pressure when this object no longer needs
* to be written to.
*/
+ @FastNative
public native final void releaseTemporaryStorage();
/**
* Should be called when object is no longer needed to reduce possible memory
* pressure if the Java GC does not get to this object in time.
*/
+ @FastNative
public native final void release();
/**
@@ -597,6 +646,7 @@
// Returns address of the "freeFunction".
private static native final long native_init();
+ @FastNative
private native final void native_setup(boolean allocate);
static {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 3fa914f..d6a35e1 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -16,6 +16,7 @@
package android.util;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -303,6 +304,18 @@
}
/**
+ * Create a new ArraySet with items from the given array
+ */
+ public ArraySet(@Nullable E[] array) {
+ this();
+ if (array != null) {
+ for (E value : array) {
+ add(value);
+ }
+ }
+ }
+
+ /**
* Make the array map empty. All storage is released.
*/
@Override
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06503bd..8336f54 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -433,6 +433,14 @@
-->
</string-array>
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
<!-- If the mobile hotspot feature requires provisioning, a package name and class name
can be provided to launch a supported application that provisions the devices.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 61077af..0bd5e43 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -743,6 +743,7 @@
<java-symbol type="string" name="config_default_dns_server" />
<java-symbol type="string" name="config_ethernet_iface_regex" />
<java-symbol type="array" name="config_ethernet_interfaces" />
+ <java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
<java-symbol type="string" name="config_mms_user_agent_profile_url" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 51da0c8..39bf742 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -611,6 +611,10 @@
}
@Override
+ public void attachStartupAgents(String s) throws RemoteException {
+ }
+
+ @Override
public void scheduleApplicationInfoChanged(ApplicationInfo applicationInfo)
throws RemoteException {
}
diff --git a/mime/Android.bp b/mime/Android.bp
index 8b2b059..23a8fbf 100644
--- a/mime/Android.bp
+++ b/mime/Android.bp
@@ -60,7 +60,7 @@
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-res.jar"],
cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/",
}
@@ -73,42 +73,49 @@
tools: [
"soong_zip",
],
- srcs: [":mime.types"],
+ srcs: [":mime.types.minimized"],
out: ["mimemap-testing-res.jar"],
cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/",
}
-// Combination of all *mime.types resources.
+// Combination of all *mime.types.minimized resources.
filegroup {
- name: "mime.types",
+ name: "mime.types.minimized",
visibility: [
"//visibility:private",
],
srcs: [
- ":debian.mime.types",
- ":android.mime.types",
- ":vendor.mime.types",
+ ":debian.mime.types.minimized",
+ ":android.mime.types.minimized",
+ ":vendor.mime.types.minimized",
],
}
-filegroup {
- name: "android.mime.types",
+java_genrule {
+ name: "android.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["android.mime.types"],
srcs: [
"java-res/android.mime.types",
],
+ // strip comments normalize whitepace drop empty lines
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' > $(out)",
}
-filegroup {
- name: "vendor.mime.types",
+// Unlike the other *mime.types files, vendor.mime.types gets '?' prepended to
+// every field so that its mappings will never overwrite earlier mappings by
+// the other resource files. http://b/141842825
+java_genrule {
+ name: "vendor.mime.types.minimized",
visibility: [
"//visibility:private",
],
- path: "java-res/",
+ out: ["vendor.mime.types"],
srcs: [
"java-res/vendor.mime.types",
],
+ // strip comments normalize whitepace drop empty lines prepend ? to fields that are missing it
+ cmd: "awk '{gsub(/#.*$$/,\"\"); $$1=$$1; print;}' $(in) | grep ' ' | awk '{for(i=1;i<=NF;i++) { sub(/^\\??/, \"?\", $$i); }; print}' > $(out)",
}
diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java
index 03b685d..11d20d4 100644
--- a/mime/java/android/content/type/DefaultMimeMapFactory.java
+++ b/mime/java/android/content/type/DefaultMimeMapFactory.java
@@ -23,11 +23,9 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
-import java.util.regex.Pattern;
/**
* Creates the framework default {@link MimeMap}, a bidirectional mapping
@@ -53,8 +51,6 @@
return create(resourceName -> c.getResourceAsStream("/res/" + resourceName));
}
- private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
-
/**
* Creates a {@link MimeMap} instance whose resources are loaded from the
* InputStreams looked up in {@code resourceSupplier}.
@@ -63,33 +59,43 @@
*/
public static MimeMap create(Function<String, InputStream> resourceSupplier) {
MimeMap.Builder builder = MimeMap.builder();
- parseTypes(builder, true, resourceSupplier, "mime.types");
- parseTypes(builder, true, resourceSupplier, "android.mime.types");
- parseTypes(builder, false, resourceSupplier, "vendor.mime.types");
+ // The files loaded here must be in minimized format with lines of the
+ // form "mime/type ext1 ext2 ext3", i.e. no comments, no empty lines, no
+ // leading/trailing whitespace and with a single space between entries on
+ // each line. See http://b/142267887
+ //
+ // Note: the order here matters - later entries can overwrite earlier ones
+ // (except that vendor.mime.types entries are prefixed with '?' which makes
+ // them never overwrite).
+ parseTypes(builder, resourceSupplier, "debian.mime.types");
+ parseTypes(builder, resourceSupplier, "android.mime.types");
+ parseTypes(builder, resourceSupplier, "vendor.mime.types");
return builder.build();
}
- private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite,
+ private static void parseTypes(MimeMap.Builder builder,
Function<String, InputStream> resourceSupplier, String resourceName) {
try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName));
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
+ List<String> specs = new ArrayList<>(10); // re-use for each line
while ((line = reader.readLine()) != null) {
- int commentPos = line.indexOf('#');
- if (commentPos >= 0) {
- line = line.substring(0, commentPos);
- }
- line = line.trim();
- if (line.isEmpty()) {
- continue;
- }
- List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
- if (!allowOverwrite) {
- // Pretend that the mimeType and each file extension listed in the line
- // carries a "?" prefix, which means that it can add new mappings but
- // not modify existing mappings (putIfAbsent() semantics).
- specs = ensurePrefix("?", specs);
- }
+ specs.clear();
+ // Lines are of the form "mimeSpec extSpec extSpec[...]" with a single space
+ // separating them and no leading/trailing spaces and no empty lines.
+ int startIdx = 0;
+ do {
+ int endIdx = line.indexOf(' ', startIdx);
+ if (endIdx < 0) {
+ endIdx = line.length();
+ }
+ String spec = line.substring(startIdx, endIdx);
+ if (spec.isEmpty()) {
+ throw new IllegalArgumentException("Malformed line: " + line);
+ }
+ specs.add(spec);
+ startIdx = endIdx + 1; // skip over the space
+ } while (startIdx < line.length());
builder.put(specs.get(0), specs.subList(1, specs.size()));
}
} catch (IOException | RuntimeException e) {
@@ -97,15 +103,4 @@
}
}
- private static List<String> ensurePrefix(String prefix, List<String> strings) {
- List<String> result = new ArrayList<>(strings.size());
- for (String s : strings) {
- if (!s.startsWith(prefix)) {
- s = prefix + s;
- }
- result.add(s);
- }
- return result;
- }
-
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9acafae..e0f60b4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -579,6 +579,8 @@
// the set of network types that can only be enabled by system/sig apps
private List mProtectedNetworks;
+ private Set<String> mWolSupportedInterfaces;
+
private TelephonyManager mTelephonyManager;
private KeepaliveTracker mKeepaliveTracker;
@@ -1055,6 +1057,10 @@
}
}
+ mWolSupportedInterfaces = new ArraySet(
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces));
+
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
@@ -3268,7 +3274,8 @@
final NetworkRequestInfo nri = mNetworkRequests.get(request);
if (nri != null) {
- if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
+ if (Process.SYSTEM_UID != callingUid && Process.NETWORK_STACK_UID != callingUid
+ && nri.mUid != callingUid) {
log(String.format("UID %d attempted to %s for unowned request %s",
callingUid, requestedOperation, nri));
return null;
@@ -5599,6 +5606,9 @@
} else {
updateProxy(newLp, oldLp);
}
+
+ updateWakeOnLan(newLp);
+
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) {
@@ -5769,6 +5779,10 @@
}
}
+ private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
+ }
+
private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
return INetd.PERMISSION_SYSTEM;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e462c7d..938528d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -271,8 +271,8 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.provider.DeviceConfig.Properties;
+import android.provider.Settings;
import android.server.ServerProtoEnums;
import android.sysprop.VoldProperties;
import android.text.TextUtils;
@@ -5013,7 +5013,9 @@
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
-
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ thread.attachStartupAgents(app.info.dataDir);
+ }
// Figure out whether the app needs to run in autofill compat mode.
AutofillOptions autofillOptions = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 44338ac..5ce215b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -93,9 +93,11 @@
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.PrintWriterPrinter;
+import android.util.SparseArray;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
@@ -129,6 +131,7 @@
private static final String STDIN_PATH = "-";
/** Path where ART profiles snapshots are dumped for the shell user */
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
+ private static final int DEFAULT_WAIT_MS = 60 * 1000;
final IPackageManager mInterface;
final private WeakHashMap<String, Resources> mResourceCache =
@@ -269,7 +272,7 @@
case "get-harmful-app-warning":
return runGetHarmfulAppWarning();
case "get-stagedsessions":
- return getStagedSessions();
+ return runListStagedSessions();
case "uninstall-system-updates":
return uninstallSystemUpdates();
case "rollback-app":
@@ -341,28 +344,6 @@
return 1;
}
- private int getStagedSessions() {
- final PrintWriter pw = getOutPrintWriter();
- try {
- List<SessionInfo> stagedSessionsList =
- mInterface.getPackageInstaller().getStagedSessions().getList();
- for (SessionInfo session: stagedSessionsList) {
- pw.println("appPackageName = " + session.getAppPackageName()
- + "; sessionId = " + session.getSessionId()
- + "; isStaged = " + session.isStaged()
- + "; isStagedSessionReady = " + session.isStagedSessionReady()
- + "; isStagedSessionApplied = " + session.isStagedSessionApplied()
- + "; isStagedSessionFailed = " + session.isStagedSessionFailed() + ";");
- }
- } catch (RemoteException e) {
- pw.println("Failure ["
- + e.getClass().getName() + " - "
- + e.getMessage() + "]");
- return 0;
- }
- return 1;
- }
-
private int uninstallSystemUpdates() {
final PrintWriter pw = getOutPrintWriter();
List<String> failedUninstalls = new LinkedList<>();
@@ -535,6 +516,8 @@
return runListPermissionGroups();
case "permissions":
return runListPermissions();
+ case "staged-sessions":
+ return runListStagedSessions();
case "users":
ServiceManager.getService("user").shellCommand(
getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(),
@@ -871,6 +854,103 @@
return 0;
}
+ private static class SessionDump {
+ boolean onlyParent; // Show parent sessions only
+ boolean onlyReady; // Show only staged sessions that are in ready state
+ boolean onlySessionId; // Show sessionId only
+ }
+
+ // Returns true if the provided flag is a session flag and given SessionDump was updated
+ private boolean setSessionFlag(String flag, SessionDump sessionDump) {
+ switch (flag) {
+ case "--only-parent":
+ sessionDump.onlyParent = true;
+ break;
+ case "--only-ready":
+ sessionDump.onlyReady = true;
+ break;
+ case "--only-sessionid":
+ sessionDump.onlySessionId = true;
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ private int runListStagedSessions() {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(
+ getOutPrintWriter(), /* singleIndent */ " ", /* wrapLength */ 120);
+
+ SessionDump sessionDump = new SessionDump();
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (!setSessionFlag(opt, sessionDump)) {
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ try {
+ List<SessionInfo> stagedSessions =
+ mInterface.getPackageInstaller().getStagedSessions().getList();
+ printSessionList(pw, stagedSessions, sessionDump);
+ } catch (RemoteException e) {
+ pw.println("Failure ["
+ + e.getClass().getName() + " - "
+ + e.getMessage() + "]");
+ return -1;
+ }
+ return 1;
+ }
+
+ private void printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions,
+ SessionDump sessionDump) {
+ final SparseArray<SessionInfo> sessionById = new SparseArray<>(stagedSessions.size());
+ for (SessionInfo session : stagedSessions) {
+ sessionById.put(session.getSessionId(), session);
+ }
+ for (SessionInfo session: stagedSessions) {
+ if (sessionDump.onlyReady && !session.isStagedSessionReady()) {
+ continue;
+ }
+ if (session.getParentSessionId() != SessionInfo.INVALID_ID) {
+ continue;
+ }
+ printSession(pw, session, sessionDump);
+ if (session.isMultiPackage() && !sessionDump.onlyParent) {
+ pw.increaseIndent();
+ final int[] childIds = session.getChildSessionIds();
+ for (int i = 0; i < childIds.length; i++) {
+ final SessionInfo childSession = sessionById.get(childIds[i]);
+ if (childSession == null) {
+ if (sessionDump.onlySessionId) {
+ pw.println(childIds[i]);
+ } else {
+ pw.println("sessionId = " + childIds[i] + "; not found");
+ }
+ } else {
+ printSession(pw, childSession, sessionDump);
+ }
+ }
+ pw.decreaseIndent();
+ }
+ }
+ }
+
+ private static void printSession(PrintWriter pw, SessionInfo session, SessionDump sessionDump) {
+ if (sessionDump.onlySessionId) {
+ pw.println(session.getSessionId());
+ return;
+ }
+ pw.println("sessionId = " + session.getSessionId()
+ + "; appPackageName = " + session.getAppPackageName()
+ + "; isStaged = " + session.isStaged()
+ + "; isReady = " + session.isStagedSessionReady()
+ + "; isApplied = " + session.isStagedSessionApplied()
+ + "; isFailed = " + session.isStagedSessionFailed() + ";");
+ }
+
private Intent parseIntentAndUser() throws URISyntaxException {
mTargetUser = UserHandle.USER_CURRENT;
mBrief = false;
@@ -1078,6 +1158,45 @@
return 1;
}
abandonSession = false;
+
+ if (!params.sessionParams.isStaged || !params.waitForStagedSessionReady) {
+ pw.println("Success");
+ return 0;
+ }
+
+ long timeoutMs = params.timeoutMs <= 0
+ ? DEFAULT_WAIT_MS
+ : params.timeoutMs;
+ PackageInstaller.SessionInfo si = mInterface.getPackageInstaller()
+ .getSessionInfo(sessionId);
+ long currentTime = System.currentTimeMillis();
+ long endTime = currentTime + timeoutMs;
+ // Using a loop instead of BroadcastReceiver since we can receive session update
+ // broadcast only if packageInstallerName is "android". We can't always force
+ // "android" as packageIntallerName, e.g, rollback auto implies
+ // "-i com.android.shell".
+ while (currentTime < endTime) {
+ if (si != null
+ && (si.isStagedSessionReady() || si.isStagedSessionFailed())) {
+ break;
+ }
+ SystemClock.sleep(Math.min(endTime - currentTime, 100));
+ currentTime = System.currentTimeMillis();
+ si = mInterface.getPackageInstaller().getSessionInfo(sessionId);
+ }
+ if (si == null) {
+ pw.println("Failure [failed to retrieve SessionInfo]");
+ return 1;
+ }
+ if (!si.isStagedSessionReady() && !si.isStagedSessionFailed()) {
+ pw.println("Failure [timed out after " + timeoutMs + " ms]");
+ return 1;
+ }
+ if (!si.isStagedSessionReady()) {
+ pw.println("Error [" + si.getStagedSessionErrorCode() + "] ["
+ + si.getStagedSessionErrorMessage() + "]");
+ return 1;
+ }
pw.println("Success");
return 0;
} finally {
@@ -2368,6 +2487,8 @@
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
+ boolean waitForStagedSessionReady = false;
+ long timeoutMs = DEFAULT_WAIT_MS;
}
private InstallParams makeInstallParams() {
@@ -2493,6 +2614,14 @@
}
sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
break;
+ case "--wait":
+ params.waitForStagedSessionReady = true;
+ try {
+ params.timeoutMs = Long.parseLong(peekNextArg());
+ getNextArg();
+ } catch (NumberFormatException ignore) {
+ }
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -3023,6 +3152,12 @@
pw.println(" -d: only list dangerous permissions");
pw.println(" -u: list only the permissions users will see");
pw.println("");
+ pw.println(" list staged-sessions [--only-ready] [--only-sessionid] [--only-parent]");
+ pw.println(" Displays list of all staged sessions on device.");
+ pw.println(" --only-ready: show only staged sessions that are ready");
+ pw.println(" --only-sessionid: show only sessionId of each session");
+ pw.println(" --only-parent: hide all children sessions");
+ pw.println("");
pw.println(" resolve-activity [--brief] [--components] [--query-flags FLAGS]");
pw.println(" [--user USER_ID] INTENT");
pw.println(" Prints the activity that resolves to the given INTENT.");
@@ -3045,7 +3180,8 @@
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
pw.println(" [--enable-rollback]");
- pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [--apex]");
+ pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+ pw.println(" [--apex] [--wait TIMEOUT]");
pw.println(" [PATH|-]");
pw.println(" Install an application. Must provide the apk data to install, either as a");
pw.println(" file path or '-' to read from stdin. Options are:");
@@ -3075,6 +3211,9 @@
pw.println(" 3=device setup, 4=user request");
pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk");
+ pw.println(" --wait: when performing staged install, wait TIMEOUT milliseconds");
+ pw.println(" for pre-reboot verification to complete. If TIMEOUT is not");
+ pw.println(" specified it will wait for " + DEFAULT_WAIT_MS + " milliseconds.");
pw.println("");
pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
@@ -3257,7 +3396,7 @@
pw.println(" uninstall-system-updates");
pw.println(" Remove updates to all system applications and fall back to their /system " +
"version.");
- pw.println();
+ pw.println("");
pw.println(" get-moduleinfo [--all | --installed] [module-name]");
pw.println(" Displays module info. If module-name is specified only that info is shown");
pw.println(" By default, without any argument only installed modules are shown.");
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 28747da..9ff8515 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -104,7 +104,7 @@
private final Looper mLooper;
private final Messenger mMessenger;
- private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
+ private final SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
public TelephonyScanManager() {
HandlerThread thread = new HandlerThread(TAG);
@@ -204,14 +204,16 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
+ synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
+ saveScanInfo(scanId, request, executor, callback);
+ return new NetworkScan(scanId, subId);
}
- saveScanInfo(scanId, request, executor, callback);
- return new NetworkScan(scanId, subId);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "requestNetworkScan RemoteException", ex);
@@ -223,9 +225,7 @@
private void saveScanInfo(
int id, NetworkScanRequest request, Executor executor, NetworkScanCallback callback) {
- synchronized (mScanInfo) {
- mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
- }
+ mScanInfo.put(id, new NetworkScanInfo(request, executor, callback));
}
private ITelephony getITelephony() {
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index d5061a3..f8621c9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -159,7 +159,7 @@
public static final int RIL_CARD_MAX_APPS = 8;
- public static final int DEFAULT_CARD_INDEX = 0;
+ public static final int DEFAULT_SLOT_INDEX = 0;
public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index b0464d9..ae8285b 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -99,6 +99,7 @@
assertFalse(lp.isIpv4Provisioned());
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
+ assertFalse(lp.isWakeOnLanSupported());
}
private LinkProperties makeTestObject() {
@@ -120,6 +121,7 @@
lp.setMtu(MTU);
lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
+ lp.setWakeOnLanSupported(true);
return lp;
}
@@ -158,6 +160,9 @@
assertTrue(source.isIdenticalTcpBufferSizes(target));
assertTrue(target.isIdenticalTcpBufferSizes(source));
+ assertTrue(source.isIdenticalWakeOnLan(target));
+ assertTrue(target.isIdenticalWakeOnLan(source));
+
// Check result of equals().
assertTrue(source.equals(target));
assertTrue(target.equals(source));
@@ -1057,4 +1062,13 @@
lp.clear();
assertFalse(lp.isPrivateDnsActive());
}
+
+ @Test
+ public void testWakeOnLanSupported() {
+ final LinkProperties lp = makeTestObject();
+ assertTrue(lp.isWakeOnLanSupported());
+
+ lp.clear();
+ assertFalse(lp.isWakeOnLanSupported());
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 41440ab..bffbbfd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -274,6 +274,7 @@
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
+ private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
@@ -343,6 +344,12 @@
"mobile_mms,2,0,2,60000,true",
});
+ when(mResources.getStringArray(
+ com.android.internal.R.array.config_wakeonlan_supported_interfaces))
+ .thenReturn(new String[]{
+ WIFI_WOL_IFNAME,
+ });
+
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -5947,6 +5954,24 @@
assertContainsExactly(uidCaptor.getValue(), APP2_UID);
}
+ @Test
+ public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+ LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
+ wifiLp.setWakeOnLanSupported(false);
+
+ // Default network switch should update ifaces.
+ mWiFiNetworkAgent.connect(false);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ waitForIdle();
+
+ // ConnectivityService should have changed the WakeOnLanSupported to true
+ wifiLp.setWakeOnLanSupported(true);
+ assertEquals(wifiLp, mService.getActiveLinkProperties());
+ }
+
private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
Set<UidRange> vpnRange) throws Exception {