Merge "Ensure inner classes of @SystemApi classes are kept" into main
diff --git a/Android.bp b/Android.bp
index 1fb50b6..1aa297f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -396,6 +396,7 @@
         "soundtrigger_middleware-aidl-java",
         "modules-utils-binary-xml",
         "modules-utils-build",
+        "modules-utils-fastxmlserializer",
         "modules-utils-preconditions",
         "modules-utils-statemachine",
         "modules-utils-synchronous-result-receiver",
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index a4a0b4b..83ad736 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -26,6 +26,10 @@
         "unsupportedappusage",
     ],
 
+    static_libs: [
+        "modules-utils-fastxmlserializer",
+    ],
+
     // Rename classes shared with the framework
     jarjar_rules: "jarjar-rules.txt",
 
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 26b7581..b6789aa 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -226,7 +226,6 @@
         "com/android/internal/util/ConcurrentUtils.java",
         "com/android/internal/util/DumpUtils.java",
         "com/android/internal/util/FastPrintWriter.java",
-        "com/android/internal/util/FastXmlSerializer.java",
         "com/android/internal/util/FunctionalUtils.java",
         "com/android/internal/util/ParseUtils.java",
         "com/android/internal/util/RingBufferIndices.java",
@@ -455,7 +454,6 @@
         "com/android/internal/util/AsyncChannel.java",
         "com/android/internal/util/AsyncService.java",
         "com/android/internal/util/BitwiseInputStream.java",
-        "com/android/internal/util/FastXmlSerializer.java",
         "com/android/internal/util/HexDump.java",
         "com/android/internal/util/IndentingPrintWriter.java",
         "com/android/internal/util/UserIcons.java",
@@ -505,7 +503,6 @@
         "android/net/InterfaceConfiguration.java",
         "android/util/BackupUtils.java",
         "android/util/Rational.java",
-        "com/android/internal/util/FastXmlSerializer.java",
         "com/android/internal/util/HexDump.java",
         "com/android/internal/util/MessageUtils.java",
         "com/android/internal/util/WakeupMessage.java",
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
deleted file mode 100644
index 929c9e8..0000000
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.compat.annotation.UnsupportedAppUsage;
-
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-
-/**
- * This is a quick and dirty implementation of XmlSerializer that isn't horribly
- * painfully slow like the normal one.  It only does what is needed for the
- * specific XML files being written with it.
- */
-public class FastXmlSerializer implements XmlSerializer {
-    private static final String ESCAPE_TABLE[] = new String[] {
-        "�",   "",   "",   "",  "",    "",   "",  "",  // 0-7
-        "",   "	",   "
",  "", "",   "
",  "", "", // 8-15
-        "",  "",  "",  "", "",   "",  "", "", // 16-23
-        "",  "",  "",  "", "",   "",  "", "", // 24-31
-        null,     null,     """, null,     null,     null,     "&",  null,   // 32-39
-        null,     null,     null,     null,     null,     null,     null,     null,   // 40-47
-        null,     null,     null,     null,     null,     null,     null,     null,   // 48-55
-        null,     null,     null,     null,     "<",   null,     ">",   null,   // 56-63
-    };
-
-    private static final int DEFAULT_BUFFER_LEN = 32*1024;
-
-    private static String sSpace = "                                                              ";
-
-    private final int mBufferLen;
-    private final char[] mText;
-    private int mPos;
-
-    private Writer mWriter;
-
-    private OutputStream mOutputStream;
-    private CharsetEncoder mCharset;
-    private ByteBuffer mBytes;
-
-    private boolean mIndent = false;
-    private boolean mInTag;
-
-    private int mNesting = 0;
-    private boolean mLineStart = true;
-
-    @UnsupportedAppUsage
-    public FastXmlSerializer() {
-        this(DEFAULT_BUFFER_LEN);
-    }
-
-    /**
-     * Allocate a FastXmlSerializer with the given internal output buffer size.  If the
-     * size is zero or negative, then the default buffer size will be used.
-     *
-     * @param bufferSize Size in bytes of the in-memory output buffer that the writer will use.
-     */
-    public FastXmlSerializer(int bufferSize) {
-        mBufferLen = (bufferSize > 0) ? bufferSize : DEFAULT_BUFFER_LEN;
-        mText = new char[mBufferLen];
-        mBytes = ByteBuffer.allocate(mBufferLen);
-    }
-
-    private void append(char c) throws IOException {
-        int pos = mPos;
-        if (pos >= (mBufferLen-1)) {
-            flush();
-            pos = mPos;
-        }
-        mText[pos] = c;
-        mPos = pos+1;
-    }
-
-    private void append(String str, int i, final int length) throws IOException {
-        if (length > mBufferLen) {
-            final int end = i + length;
-            while (i < end) {
-                int next = i + mBufferLen;
-                append(str, i, next<end ? mBufferLen : (end-i));
-                i = next;
-            }
-            return;
-        }
-        int pos = mPos;
-        if ((pos+length) > mBufferLen) {
-            flush();
-            pos = mPos;
-        }
-        str.getChars(i, i+length, mText, pos);
-        mPos = pos + length;
-    }
-
-    private void append(char[] buf, int i, final int length) throws IOException {
-        if (length > mBufferLen) {
-            final int end = i + length;
-            while (i < end) {
-                int next = i + mBufferLen;
-                append(buf, i, next<end ? mBufferLen : (end-i));
-                i = next;
-            }
-            return;
-        }
-        int pos = mPos;
-        if ((pos+length) > mBufferLen) {
-            flush();
-            pos = mPos;
-        }
-        System.arraycopy(buf, i, mText, pos, length);
-        mPos = pos + length;
-    }
-
-    private void append(String str) throws IOException {
-        append(str, 0, str.length());
-    }
-
-    private void appendIndent(int indent) throws IOException {
-        indent *= 4;
-        if (indent > sSpace.length()) {
-            indent = sSpace.length();
-        }
-        append(sSpace, 0, indent);
-    }
-
-    private void escapeAndAppendString(final String string) throws IOException {
-        final int N = string.length();
-        final char NE = (char)ESCAPE_TABLE.length;
-        final String[] escapes = ESCAPE_TABLE;
-        int lastPos = 0;
-        int pos;
-        for (pos=0; pos<N; pos++) {
-            char c = string.charAt(pos);
-            if (c >= NE) continue;
-            String escape = escapes[c];
-            if (escape == null) continue;
-            if (lastPos < pos) append(string, lastPos, pos-lastPos);
-            lastPos = pos + 1;
-            append(escape);
-        }
-        if (lastPos < pos) append(string, lastPos, pos-lastPos);
-    }
-
-    private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
-        final char NE = (char)ESCAPE_TABLE.length;
-        final String[] escapes = ESCAPE_TABLE;
-        int end = start+len;
-        int lastPos = start;
-        int pos;
-        for (pos=start; pos<end; pos++) {
-            char c = buf[pos];
-            if (c >= NE) continue;
-            String escape = escapes[c];
-            if (escape == null) continue;
-            if (lastPos < pos) append(buf, lastPos, pos-lastPos);
-            lastPos = pos + 1;
-            append(escape);
-        }
-        if (lastPos < pos) append(buf, lastPos, pos-lastPos);
-    }
-
-    public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        append(' ');
-        if (namespace != null) {
-            append(namespace);
-            append(':');
-        }
-        append(name);
-        append("=\"");
-
-        escapeAndAppendString(value);
-        append('"');
-        mLineStart = false;
-        return this;
-    }
-
-    public void cdsect(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void comment(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void docdecl(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
-        flush();
-    }
-
-    public XmlSerializer endTag(String namespace, String name) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        mNesting--;
-        if (mInTag) {
-            append(" />\n");
-        } else {
-            if (mIndent && mLineStart) {
-                appendIndent(mNesting);
-            }
-            append("</");
-            if (namespace != null) {
-                append(namespace);
-                append(':');
-            }
-            append(name);
-            append(">\n");
-        }
-        mLineStart = true;
-        mInTag = false;
-        return this;
-    }
-
-    public void entityRef(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    private void flushBytes() throws IOException {
-        int position;
-        if ((position = mBytes.position()) > 0) {
-            mBytes.flip();
-            mOutputStream.write(mBytes.array(), 0, position);
-            mBytes.clear();
-        }
-    }
-
-    public void flush() throws IOException {
-        //Log.i("PackageManager", "flush mPos=" + mPos);
-        if (mPos > 0) {
-            if (mOutputStream != null) {
-                CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
-                CoderResult result = mCharset.encode(charBuffer, mBytes, true);
-                while (true) {
-                    if (result.isError()) {
-                        throw new IOException(result.toString());
-                    } else if (result.isOverflow()) {
-                        flushBytes();
-                        result = mCharset.encode(charBuffer, mBytes, true);
-                        continue;
-                    }
-                    break;
-                }
-                flushBytes();
-                mOutputStream.flush();
-            } else {
-                mWriter.write(mText, 0, mPos);
-                mWriter.flush();
-            }
-            mPos = 0;
-        }
-    }
-
-    public int getDepth() {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean getFeature(String name) {
-        throw new UnsupportedOperationException();
-    }
-
-    public String getName() {
-        throw new UnsupportedOperationException();
-    }
-
-    public String getNamespace() {
-        throw new UnsupportedOperationException();
-    }
-
-    public String getPrefix(String namespace, boolean generatePrefix)
-            throws IllegalArgumentException {
-        throw new UnsupportedOperationException();
-    }
-
-    public Object getProperty(String name) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void processingInstruction(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setFeature(String name, boolean state) throws IllegalArgumentException,
-            IllegalStateException {
-        if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
-            mIndent = true;
-            return;
-        }
-        throw new UnsupportedOperationException();
-    }
-
-    public void setOutput(OutputStream os, String encoding) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        if (os == null)
-            throw new IllegalArgumentException();
-        if (true) {
-            try {
-                mCharset = Charset.forName(encoding).newEncoder()
-                        .onMalformedInput(CodingErrorAction.REPLACE)
-                        .onUnmappableCharacter(CodingErrorAction.REPLACE);
-            } catch (IllegalCharsetNameException e) {
-                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
-                        encoding).initCause(e));
-            } catch (UnsupportedCharsetException e) {
-                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
-                        encoding).initCause(e));
-            }
-            mOutputStream = os;
-        } else {
-            setOutput(
-                encoding == null
-                    ? new OutputStreamWriter(os)
-                    : new OutputStreamWriter(os, encoding));
-        }
-    }
-
-    public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        mWriter = writer;
-    }
-
-    public void setPrefix(String prefix, String namespace) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setProperty(String name, Object value) throws IllegalArgumentException,
-            IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    public void startDocument(String encoding, Boolean standalone) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        append("<?xml version='1.0' encoding='utf-8'");
-        if (standalone != null) {
-            append(" standalone='" + (standalone ? "yes" : "no") + "'");
-        }
-        append(" ?>\n");
-        mLineStart = true;
-    }
-
-    public XmlSerializer startTag(String namespace, String name) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        if (mInTag) {
-            append(">\n");
-        }
-        if (mIndent) {
-            appendIndent(mNesting);
-        }
-        mNesting++;
-        append('<');
-        if (namespace != null) {
-            append(namespace);
-            append(':');
-        }
-        append(name);
-        mInTag = true;
-        mLineStart = false;
-        return this;
-    }
-
-    public XmlSerializer text(char[] buf, int start, int len) throws IOException,
-            IllegalArgumentException, IllegalStateException {
-        if (mInTag) {
-            append(">");
-            mInTag = false;
-        }
-        escapeAndAppendString(buf, start, len);
-        if (mIndent) {
-            mLineStart = buf[start+len-1] == '\n';
-        }
-        return this;
-    }
-
-    public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
-            IllegalStateException {
-        if (mInTag) {
-            append(">");
-            mInTag = false;
-        }
-        escapeAndAppendString(text);
-        if (mIndent) {
-            mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\n');
-        }
-        return this;
-    }
-
-}
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 0df7c20..f24c3f5 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -1,5 +1,6 @@
 adamp@google.com
 asc@google.com
+austindelgado@google.com
 cinek@google.com
 dsandler@android.com
 dsandler@google.com
@@ -8,6 +9,7 @@
 hackbod@google.com
 ilyamaty@google.com
 jaggies@google.com
+jbolinger@google.com
 jsharkey@android.com
 jsharkey@google.com
 juliacr@google.com
diff --git a/services/companion/java/com/android/server/companion/virtual/OWNERS b/services/companion/java/com/android/server/companion/virtual/OWNERS
index 83143a4..5295ec8 100644
--- a/services/companion/java/com/android/server/companion/virtual/OWNERS
+++ b/services/companion/java/com/android/server/companion/virtual/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1171888
+
 set noparent
 
 ogunwale@google.com
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 53fbe8f..a12243b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,7 +22,6 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
 import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
@@ -45,12 +44,10 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -113,7 +110,6 @@
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.CancellationSignal;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -152,7 +148,6 @@
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
-import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.BinderUtils;
 import com.android.net.module.util.LinkPropertiesUtils;
 import com.android.net.module.util.NetdUtils;
@@ -202,7 +197,6 @@
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * @hide
@@ -1063,8 +1057,6 @@
         // Store mPackage since it might be reset or might be replaced with the other VPN app.
         final String oldPackage = mPackage;
         final boolean isPackageChanged = !Objects.equals(packageName, oldPackage);
-        // TODO: Remove "SdkLevel.isAtLeastT()" check once VpnManagerService is decoupled from
-        //  ConnectivityServiceTest.
         // Only notify VPN apps that were already always-on, and only if the always-on provider
         // changed, or the lockdown mode changed.
         final boolean shouldNotifyOldPkg = isVpnApp(oldPackage) && mAlwaysOn
@@ -1078,12 +1070,6 @@
 
         saveAlwaysOnPackage();
 
-        // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
-        //  ConnectivityServiceTest.
-        if (!SdkLevel.isAtLeastT()) {
-            return true;
-        }
-
         if (shouldNotifyOldPkg) {
             // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the
             // always-on of old package is disabled or the old package is replaced with the new
@@ -1984,9 +1970,7 @@
         for (String app : packageNames) {
             int uid = getAppUid(mContext, app, userId);
             if (uid != -1) uids.add(uid);
-            // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
-            // ConnectivityServiceTest.
-            if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) {
+            if (Process.isApplicationUid(uid)) {
                 uids.add(Process.toSdkSandboxUid(uid));
             }
         }
@@ -2297,15 +2281,6 @@
 
     private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
         @Override
-        public void interfaceStatusChanged(String interfaze, boolean up) {
-            synchronized (Vpn.this) {
-                if (!up && mVpnRunner != null && mVpnRunner instanceof LegacyVpnRunner) {
-                    ((LegacyVpnRunner) mVpnRunner).exitIfOuterInterfaceIs(interfaze);
-                }
-            }
-        }
-
-        @Override
         public void interfaceRemoved(String interfaze) {
             synchronized (Vpn.this) {
                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
@@ -2556,17 +2531,6 @@
     private native boolean jniAddAddress(String interfaze, String address, int prefixLen);
     private native boolean jniDelAddress(String interfaze, String address, int prefixLen);
 
-    private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
-        for (RouteInfo route : prop.getAllRoutes()) {
-            // Currently legacy VPN only works on IPv4.
-            if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) {
-                return route;
-            }
-        }
-
-        throw new IllegalStateException("Unable to find IPv4 default gateway");
-    }
-
     private void enforceNotRestrictedUser() {
         final long token = Binder.clearCallingIdentity();
         try {
@@ -2665,10 +2629,6 @@
             throw new SecurityException("Restricted users cannot establish VPNs");
         }
 
-        final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress);
-        final String gateway = ipv4DefaultRoute.getGateway().getHostAddress();
-        final String iface = ipv4DefaultRoute.getInterface();
-
         // Load certificates.
         String privateKey = "";
         String userCert = "";
@@ -2700,8 +2660,6 @@
             throw new IllegalStateException("Cannot load credentials");
         }
 
-        // Prepare arguments for racoon.
-        String[] racoon = null;
         switch (profile.type) {
             case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
                 // Secret key is still just the alias (not the actual private key). The private key
@@ -2731,109 +2689,9 @@
                 // profile.
                 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
                 return;
-            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
-                racoon = new String[] {
-                    iface, profile.server, "udppsk", profile.ipsecIdentifier,
-                    profile.ipsecSecret, "1701",
-                };
-                break;
-            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
-                racoon = new String[] {
-                    iface, profile.server, "udprsa", makeKeystoreEngineGrantString(privateKey),
-                    userCert, caCert, serverCert, "1701",
-                };
-                break;
-            case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
-                racoon = new String[] {
-                    iface, profile.server, "xauthpsk", profile.ipsecIdentifier,
-                    profile.ipsecSecret, profile.username, profile.password, "", gateway,
-                };
-                break;
-            case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
-                racoon = new String[] {
-                    iface, profile.server, "xauthrsa", makeKeystoreEngineGrantString(privateKey),
-                    userCert, caCert, serverCert, profile.username, profile.password, "", gateway,
-                };
-                break;
-            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
-                racoon = new String[] {
-                    iface, profile.server, "hybridrsa",
-                    caCert, serverCert, profile.username, profile.password, "", gateway,
-                };
-                break;
         }
 
-        // Prepare arguments for mtpd. MTU/MRU calculated conservatively. Only IPv4 supported
-        // because LegacyVpn.
-        // 1500 - 60 (Carrier-internal IPv6 + UDP + GTP) - 10 (PPP) - 16 (L2TP) - 8 (UDP)
-        //   - 77 (IPsec w/ SHA-2 512, 256b trunc-len, AES-CBC) - 8 (UDP encap) - 20 (IPv4)
-        //   - 28 (464xlat)
-        String[] mtpd = null;
-        switch (profile.type) {
-            case VpnProfile.TYPE_PPTP:
-                mtpd = new String[] {
-                    iface, "pptp", profile.server, "1723",
-                    "name", profile.username, "password", profile.password,
-                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
-                    "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270",
-                    (profile.mppe ? "+mppe" : "nomppe"),
-                };
-                if (profile.mppe) {
-                    // Disallow PAP authentication when MPPE is requested, as MPPE cannot work
-                    // with PAP anyway, and users may not expect PAP (plain text) to be used when
-                    // MPPE was requested.
-                    mtpd = Arrays.copyOf(mtpd, mtpd.length + 1);
-                    mtpd[mtpd.length - 1] = "-pap";
-                }
-                break;
-            case VpnProfile.TYPE_L2TP_IPSEC_PSK:
-            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
-                mtpd = new String[] {
-                    iface, "l2tp", profile.server, "1701", profile.l2tpSecret,
-                    "name", profile.username, "password", profile.password,
-                    "linkname", "vpn", "refuse-eap", "nodefaultroute",
-                    "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270",
-                };
-                break;
-        }
-
-        VpnConfig config = new VpnConfig();
-        config.legacy = true;
-        config.user = profile.key;
-        config.interfaze = iface;
-        config.session = profile.name;
-        config.isMetered = false;
-        config.proxyInfo = profile.proxy;
-        if (underlying != null) {
-            config.underlyingNetworks = new Network[] { underlying };
-        }
-
-        config.addLegacyRoutes(profile.routes);
-        if (!profile.dnsServers.isEmpty()) {
-            config.dnsServers = Arrays.asList(profile.dnsServers.split(" +"));
-        }
-        if (!profile.searchDomains.isEmpty()) {
-            config.searchDomains = Arrays.asList(profile.searchDomains.split(" +"));
-        }
-        startLegacyVpn(config, racoon, mtpd, profile);
-    }
-
-    private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd,
-            VpnProfile profile) {
-        stopVpnRunnerPrivileged();
-
-        // Prepare for the new request.
-        prepareInternal(VpnConfig.LEGACY_VPN);
-        updateState(DetailedState.CONNECTING, "startLegacyVpn");
-
-        // Start a new LegacyVpnRunner and we are done!
-        mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
-        startLegacyVpnRunner();
-    }
-
-    @VisibleForTesting
-    protected void startLegacyVpnRunner() {
-        mVpnRunner.start();
+        throw new UnsupportedOperationException("Legacy VPN is deprecated");
     }
 
     /**
@@ -2851,17 +2709,7 @@
             return;
         }
 
-        final boolean isLegacyVpn = mVpnRunner instanceof LegacyVpnRunner;
         mVpnRunner.exit();
-
-        // LegacyVpn uses daemons that must be shut down before new ones are brought up.
-        // The same limitation does not apply to Platform VPNs.
-        if (isLegacyVpn) {
-            synchronized (LegacyVpnRunner.TAG) {
-                // wait for old thread to completely finish before spinning up
-                // new instance, otherwise state updates can be out of order.
-            }
-        }
     }
 
     /**
@@ -4143,9 +3991,7 @@
                 // Ignore stale runner.
                 if (mVpnRunner != this) return;
 
-                // TODO(b/230548427): Remove SDK check once VPN related stuff are
-                //  decoupled from ConnectivityServiceTest.
-                if (SdkLevel.isAtLeastT() && category != null && isVpnApp(mPackage)) {
+                if (category != null && isVpnApp(mPackage)) {
                     sendEventToVpnManagerApp(category, errorClass, errorCode,
                             getPackage(), mSessionKey, makeVpnProfileStateLocked(),
                             mActiveNetwork,
@@ -4256,343 +4102,6 @@
         }
     }
 
-    /**
-     * Bringing up a VPN connection takes time, and that is all this thread
-     * does. Here we have plenty of time. The only thing we need to take
-     * care of is responding to interruptions as soon as possible. Otherwise
-     * requests will pile up. This could be done in a Handler as a state
-     * machine, but it is much easier to read in the current form.
-     */
-    private class LegacyVpnRunner extends VpnRunner {
-        private static final String TAG = "LegacyVpnRunner";
-
-        private final String[] mDaemons;
-        private final String[][] mArguments;
-        private final LocalSocket[] mSockets;
-        private final String mOuterInterface;
-        private final AtomicInteger mOuterConnection =
-                new AtomicInteger(ConnectivityManager.TYPE_NONE);
-        private final VpnProfile mProfile;
-
-        private long mBringupStartTime = -1;
-
-        /**
-         * Watch for the outer connection (passing in the constructor) going away.
-         */
-        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (!mEnableTeardown) return;
-
-                if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                    if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
-                            ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) {
-                        NetworkInfo info = (NetworkInfo)intent.getExtra(
-                                ConnectivityManager.EXTRA_NETWORK_INFO);
-                        if (info != null && !info.isConnectedOrConnecting()) {
-                            try {
-                                mObserver.interfaceStatusChanged(mOuterInterface, false);
-                            } catch (RemoteException e) {}
-                        }
-                    }
-                }
-            }
-        };
-
-        // GuardedBy("Vpn.this") (annotation can't be applied to constructor)
-        LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile) {
-            super(TAG);
-            if (racoon == null && mtpd == null) {
-                throw new IllegalArgumentException(
-                        "Arguments to racoon and mtpd must not both be null");
-            }
-            mConfig = config;
-            mDaemons = new String[] {"racoon", "mtpd"};
-            // TODO: clear arguments from memory once launched
-            mArguments = new String[][] {racoon, mtpd};
-            mSockets = new LocalSocket[mDaemons.length];
-
-            // This is the interface which VPN is running on,
-            // mConfig.interfaze will change to point to OUR
-            // internal interface soon. TODO - add inner/outer to mconfig
-            // TODO - we have a race - if the outer iface goes away/disconnects before we hit this
-            // we will leave the VPN up.  We should check that it's still there/connected after
-            // registering
-            mOuterInterface = mConfig.interfaze;
-
-            mProfile = profile;
-
-            if (!TextUtils.isEmpty(mOuterInterface)) {
-                for (Network network : mConnectivityManager.getAllNetworks()) {
-                    final LinkProperties lp = mConnectivityManager.getLinkProperties(network);
-                    if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
-                        final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network);
-                        if (netInfo != null) {
-                            mOuterConnection.set(netInfo.getType());
-                            break;
-                        }
-                    }
-                }
-            }
-
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-            mContext.registerReceiver(mBroadcastReceiver, filter);
-        }
-
-        /**
-         * Checks if the parameter matches the underlying interface
-         *
-         * <p>If the underlying interface is torn down, the LegacyVpnRunner also should be. It has
-         * no ability to migrate between interfaces (or Networks).
-         */
-        public void exitIfOuterInterfaceIs(String interfaze) {
-            if (interfaze.equals(mOuterInterface)) {
-                Log.i(TAG, "Legacy VPN is going down with " + interfaze);
-                exitVpnRunner();
-            }
-        }
-
-        /** Tears down this LegacyVpn connection */
-        @Override
-        public void exitVpnRunner() {
-            // We assume that everything is reset after stopping the daemons.
-            interrupt();
-
-            // Always disconnect. This may be called again in cleanupVpnStateLocked() if
-            // exitVpnRunner() was called from exit(), but it will be a no-op.
-            agentDisconnect();
-            try {
-                mContext.unregisterReceiver(mBroadcastReceiver);
-            } catch (IllegalArgumentException e) {}
-        }
-
-        @Override
-        public void run() {
-            // Wait for the previous thread since it has been interrupted.
-            Log.v(TAG, "Waiting");
-            synchronized (TAG) {
-                Log.v(TAG, "Executing");
-                try {
-                    bringup();
-                    waitForDaemonsToStop();
-                    interrupted(); // Clear interrupt flag if execute called exit.
-                } catch (InterruptedException e) {
-                } finally {
-                    for (LocalSocket socket : mSockets) {
-                        IoUtils.closeQuietly(socket);
-                    }
-                    // This sleep is necessary for racoon to successfully complete sending delete
-                    // message to server.
-                    try {
-                        Thread.sleep(50);
-                    } catch (InterruptedException e) {
-                    }
-                    for (String daemon : mDaemons) {
-                        mDeps.stopService(daemon);
-                    }
-                }
-                agentDisconnect();
-            }
-        }
-
-        private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException {
-            long now = SystemClock.elapsedRealtime();
-            if (now - mBringupStartTime <= 60000) {
-                Thread.sleep(sleepLonger ? 200 : 1);
-            } else {
-                updateState(DetailedState.FAILED, "checkpoint");
-                throw new IllegalStateException("VPN bringup took too long");
-            }
-        }
-
-        private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) {
-            final String endpointAddressString = endpointAddress.getHostAddress();
-            // Perform some safety checks before inserting the address in place.
-            // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd.
-            if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) {
-                throw new IllegalStateException("Unexpected daemons order");
-            }
-
-            // Respectively, the positions at which racoon and mtpd take the server address
-            // argument are 1 and 2. Not all types of VPN require both daemons however, and
-            // in that case the corresponding argument array is null.
-            if (mArguments[0] != null) {
-                if (!mProfile.server.equals(mArguments[0][1])) {
-                    throw new IllegalStateException("Invalid server argument for racoon");
-                }
-                mArguments[0][1] = endpointAddressString;
-            }
-
-            if (mArguments[1] != null) {
-                if (!mProfile.server.equals(mArguments[1][2])) {
-                    throw new IllegalStateException("Invalid server argument for mtpd");
-                }
-                mArguments[1][2] = endpointAddressString;
-            }
-        }
-
-        private void bringup() {
-            // Catch all exceptions so we can clean up a few things.
-            try {
-                // resolve never returns null. If it does because of some bug, it will be
-                // caught by the catch() block below and cleanup gracefully.
-                final InetAddress endpointAddress = mDeps.resolve(mProfile.server);
-
-                // Big hack : dynamically replace the address of the server in the arguments
-                // with the resolved address.
-                checkAndFixupArguments(endpointAddress);
-
-                // Initialize the timer.
-                mBringupStartTime = SystemClock.elapsedRealtime();
-
-                // Wait for the daemons to stop.
-                for (String daemon : mDaemons) {
-                    while (!mDeps.isServiceStopped(daemon)) {
-                        checkInterruptAndDelay(true);
-                    }
-                }
-
-                // Clear the previous state.
-                final File state = mDeps.getStateFile();
-                state.delete();
-                if (state.exists()) {
-                    throw new IllegalStateException("Cannot delete the state");
-                }
-                new File("/data/misc/vpn/abort").delete();
-
-                updateState(DetailedState.CONNECTING, "execute");
-
-                // Start the daemon with arguments.
-                for (int i = 0; i < mDaemons.length; ++i) {
-                    String[] arguments = mArguments[i];
-                    if (arguments == null) {
-                        continue;
-                    }
-
-                    // Start the daemon.
-                    String daemon = mDaemons[i];
-                    mDeps.startService(daemon);
-
-                    // Wait for the daemon to start.
-                    while (!mDeps.isServiceRunning(daemon)) {
-                        checkInterruptAndDelay(true);
-                    }
-
-                    // Create the control socket.
-                    mSockets[i] = new LocalSocket();
-
-                    // Wait for the socket to connect and send over the arguments.
-                    mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments,
-                            this::checkInterruptAndDelay);
-                }
-
-                // Wait for the daemons to create the new state.
-                while (!state.exists()) {
-                    // Check if a running daemon is dead.
-                    for (int i = 0; i < mDaemons.length; ++i) {
-                        String daemon = mDaemons[i];
-                        if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) {
-                            throw new IllegalStateException(daemon + " is dead");
-                        }
-                    }
-                    checkInterruptAndDelay(true);
-                }
-
-                // Now we are connected. Read and parse the new state.
-                String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
-                if (parameters.length != 7) {
-                    throw new IllegalStateException("Cannot parse the state: '"
-                            + String.join("', '", parameters) + "'");
-                }
-
-                // Set the interface and the addresses in the config.
-                synchronized (Vpn.this) {
-                    mConfig.interfaze = parameters[0].trim();
-
-                    mConfig.addLegacyAddresses(parameters[1]);
-                    // Set the routes if they are not set in the config.
-                    if (mConfig.routes == null || mConfig.routes.isEmpty()) {
-                        mConfig.addLegacyRoutes(parameters[2]);
-                    }
-
-                    // Set the DNS servers if they are not set in the config.
-                    if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
-                        String dnsServers = parameters[3].trim();
-                        if (!dnsServers.isEmpty()) {
-                            mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
-                        }
-                    }
-
-                    // Set the search domains if they are not set in the config.
-                    if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
-                        String searchDomains = parameters[4].trim();
-                        if (!searchDomains.isEmpty()) {
-                            mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
-                        }
-                    }
-
-                    // Add a throw route for the VPN server endpoint, if one was specified.
-                    if (endpointAddress instanceof Inet4Address) {
-                        mConfig.routes.add(new RouteInfo(
-                                new IpPrefix(endpointAddress, 32), null /*gateway*/,
-                                null /*iface*/, RTN_THROW));
-                    } else if (endpointAddress instanceof Inet6Address) {
-                        mConfig.routes.add(new RouteInfo(
-                                new IpPrefix(endpointAddress, 128), null /*gateway*/,
-                                null /*iface*/, RTN_THROW));
-                    } else {
-                        Log.e(TAG, "Unknown IP address family for VPN endpoint: "
-                                + endpointAddress);
-                    }
-
-                    // Here is the last step and it must be done synchronously.
-                    // Set the start time
-                    mConfig.startTime = SystemClock.elapsedRealtime();
-
-                    // Check if the thread was interrupted while we were waiting on the lock.
-                    checkInterruptAndDelay(false);
-
-                    // Check if the interface is gone while we are waiting.
-                    if (!mDeps.isInterfacePresent(Vpn.this, mConfig.interfaze)) {
-                        throw new IllegalStateException(mConfig.interfaze + " is gone");
-                    }
-
-                    // Now INetworkManagementEventObserver is watching our back.
-                    mInterface = mConfig.interfaze;
-                    prepareStatusIntent();
-
-                    agentConnect();
-
-                    Log.i(TAG, "Connected!");
-                }
-            } catch (Exception e) {
-                Log.i(TAG, "Aborting", e);
-                updateState(DetailedState.FAILED, e.getMessage());
-                exitVpnRunner();
-            }
-        }
-
-        /**
-         * Check all daemons every two seconds. Return when one of them is stopped.
-         * The caller will move to the disconnected state when this function returns,
-         * which can happen if a daemon failed or if the VPN was torn down.
-         */
-        private void waitForDaemonsToStop() throws InterruptedException {
-            if (!mNetworkInfo.isConnected()) {
-                return;
-            }
-            while (true) {
-                Thread.sleep(2000);
-                for (int i = 0; i < mDaemons.length; i++) {
-                    if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) {
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
     private void verifyCallingUidAndPackage(String packageName) {
         mDeps.verifyCallingUidAndPackage(mContext, packageName, mUserId);
     }
@@ -4839,11 +4348,9 @@
         // Build intent first because the sessionKey will be reset after performing
         // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in
         // VpnRunner.exit() to prevent design being changed in the future.
-        // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
-        //  ConnectivityServiceTest.
         final int ownerUid = mOwnerUID;
         Intent intent = null;
-        if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
+        if (isVpnApp(mPackage)) {
             intent = buildVpnManagerEventIntent(
                     VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
                     -1 /* errorClass */, -1 /* errorCode*/, mPackage,
@@ -4884,12 +4391,8 @@
         // The underlying network, NetworkCapabilities and LinkProperties are not
         // necessary to send to VPN app since the purpose of this event is to notify
         // VPN app that VPN is deactivated by the user.
-        // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
-        //  ConnectivityServiceTest.
-        if (SdkLevel.isAtLeastT()) {
-            mEventChanges.log("[VMEvent] " + packageName + " stopped");
-            sendEventToVpnManagerApp(intent, packageName);
-        }
+        mEventChanges.log("[VMEvent] " + packageName + " stopped");
+        sendEventToVpnManagerApp(intent, packageName);
     }
 
     private boolean storeAppExclusionList(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 46ca445..6d560e4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4626,7 +4626,7 @@
                                 // Expanding pip into new rotation, so create a rotation leash
                                 // until the display is rotated.
                                 topActivity.getOrCreateFixedRotationLeash(
-                                        topActivity.getSyncTransaction());
+                                        topActivity.getPendingTransaction());
                             }
                             lastParentBeforePip.moveToFront("movePinnedActivityToOriginalTask");
                         }