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 {