Merge "Make test_options.timeout an int64"
diff --git a/Android.bp b/Android.bp
index c46f092..126b763 100644
--- a/Android.bp
+++ b/Android.bp
@@ -669,7 +669,7 @@
             "system/security/keystore/binder",
         ],
 
-        generate_get_transaction_name: true
+        generate_get_transaction_name: true,
     },
 
     exclude_srcs: [
@@ -791,7 +791,7 @@
     name: "framework-javastream-protos",
     depfile: true,
 
-    tool_files: [ "tools/genprotos.sh", ],
+    tool_files: ["tools/genprotos.sh"],
     tools: [
         "aprotoc",
         "protoc-gen-javastream",
@@ -802,13 +802,13 @@
     // end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to
     // the way sbox rewrites the command. See b/70221552.
     cmd: "$(location tools/genprotos.sh) " +
-              " $(location aprotoc) " +
-              " $(location protoc-gen-javastream) " +
-              " $(location soong_zip) " +
-              " $(genDir) " +
-              " $(depfile) " +
-              " $(in) " +
-              " $(out)",
+        " $(location aprotoc) " +
+        " $(location protoc-gen-javastream) " +
+        " $(location soong_zip) " +
+        " $(genDir) " +
+        " $(depfile) " +
+        " $(in) " +
+        " $(out)",
     srcs: [
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
@@ -826,7 +826,7 @@
         "core/java/android/annotation/UnsupportedAppUsage.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
         "core/java/com/android/internal/annotations/VisibleForTesting.java",
-    ]
+    ],
 }
 
 filegroup {
@@ -847,7 +847,7 @@
         "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "core/java/android/net/shared/*.java",
-    ]
+    ],
 }
 
 // Build ext.jar
@@ -883,7 +883,7 @@
         type: "full",
     },
     errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"],  // b/72714520
+        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
     },
 }
 
@@ -1103,11 +1103,11 @@
 }
 
 framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
-     "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
-     "-overview $(location core/java/overview.html) " +
-     // Federate Support Library references against local API file.
-     "-federate SupportLib https://developer.android.com " +
-     "-federationapi SupportLib $(location :current-support-api) "
+    "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
+    "-overview $(location core/java/overview.html) " +
+    // Federate Support Library references against local API file.
+    "-federate SupportLib https://developer.android.com " +
+    "-federationapi SupportLib $(location :current-support-api) "
 
 framework_docs_only_libs = [
     "voip-common",
@@ -1204,7 +1204,7 @@
 doc_defaults {
     name: "framework-docs-default",
     libs: framework_docs_only_libs +
-         ["stub-annotations"],
+        ["stub-annotations"],
     html_dirs: [
         "docs/html",
     ],
@@ -1336,8 +1336,8 @@
         "android.whichdoc offline",
     ],
     proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_only_args  + " -hide 101 -hide 104 -hide 108" +
-        " -offlinemode -title \"Android System SDK\" -referenceonly",
+    args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" +
+    " -offlinemode -title \"Android System SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1354,7 +1354,7 @@
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-docs-proofrerad.txt",
-    args: framework_docs_only_args  +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1447,10 +1447,10 @@
     ],
     proofread_file: "ds-static-docs-proofrerad.txt",
     args: framework_docs_only_args +
-          " -staticonly " +
-          " -toroot / " +
-          " -devsite " +
-          " -ignoreJdLinks ",
+        " -staticonly " +
+        " -toroot / " +
+        " -devsite " +
+        " -ignoreJdLinks ",
 }
 
 droiddoc {
@@ -1464,9 +1464,9 @@
     ],
     proofread_file: "ds-ref-navtree-docs-proofrerad.txt",
     args: framework_docs_only_args +
-          " -toroot / " +
-          " -atLinksNavtree " +
-          " -navtreeonly ",
+        " -toroot / " +
+        " -atLinksNavtree " +
+        " -navtreeonly ",
 }
 
 droiddoc {
@@ -1506,8 +1506,8 @@
     ],
     proofread_file: "hidden-docs-proofrerad.txt",
     args: framework_docs_only_args +
-          " -referenceonly " +
-          " -title \"Android SDK - Including hidden APIs.\"",
+        " -referenceonly " +
+        " -title \"Android SDK - Including hidden APIs.\"",
 }
 
 droidstubs {
@@ -1559,10 +1559,9 @@
     args: metalava_framework_docs_args +
         " --show-unannotated " +
         " --show-annotation android.annotation.SystemApi " +
-        " --show-annotation android.annotation.TestApi "
+        " --show-annotation android.annotation.TestApi ",
 }
 
-
 droidstubs {
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
@@ -1581,7 +1580,7 @@
         " --hide UnhiddenSystemApi " +
         " --show-unannotated " +
         " --show-annotation android.annotation.SystemApi " +
-        " --show-annotation android.annotation.TestApi "
+        " --show-annotation android.annotation.TestApi ",
 }
 
 filegroup {
@@ -1685,5 +1684,5 @@
 aidl_mapping {
     name: "framework-aidl-mappings",
     srcs: [":framework-defaults"],
-    output: "framework-aidl-mappings.txt"
+    output: "framework-aidl-mappings.txt",
 }
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 4b2b4c3..7a85dcb 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import static android.net.NetworkUtils.getDnsNetId;
+import static android.net.NetworkUtils.getDnsNetwork;
 import static android.net.NetworkUtils.resNetworkCancel;
 import static android.net.NetworkUtils.resNetworkQuery;
 import static android.net.NetworkUtils.resNetworkResult;
@@ -333,7 +333,7 @@
         final Object lock = new Object();
         final Network queryNetwork;
         try {
-            queryNetwork = (network != null) ? network : new Network(getDnsNetId());
+            queryNetwork = (network != null) ? network : getDnsNetwork();
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
@@ -433,7 +433,7 @@
         final FileDescriptor queryfd;
         final Network queryNetwork;
         try {
-            queryNetwork = (network != null) ? network : new Network(getDnsNetId());
+            queryNetwork = (network != null) ? network : getDnsNetwork();
             queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
                     flags);
         } catch (ErrnoException e) {
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 27e0414..b27b1c0 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -1300,7 +1300,8 @@
         }
 
         final Entry tmpEntry = new Entry();
-        for (int i = 0; i < size; i++) {
+        final int origSize = size;
+        for (int i = 0; i < origSize; i++) {
             if (!Objects.equals(iface[i], tunIface)) {
                 // Consider only entries that go onto the VPN interface.
                 continue;
@@ -1316,8 +1317,9 @@
             tmpEntry.roaming = roaming[i];
             tmpEntry.defaultNetwork = defaultNetwork[i];
 
-            // In a first pass, compute each UID's total share of data across all underlyingIfaces.
-            // This is computed on the basis of the share of each UID's usage over tunIface.
+            // In a first pass, compute this entry's total share of data across all
+            // underlyingIfaces. This is computed on the basis of the share of this entry's usage
+            // over tunIface.
             // TODO: Consider refactoring first pass into a separate helper method.
             long totalRxBytes = 0;
             if (tunIfaceTotal.rxBytes > 0) {
@@ -1394,9 +1396,11 @@
                                     * perInterfaceTotal[j].operations
                                     / underlyingIfacesTotal.operations;
                 }
-
+                // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying
+                // interface. Add that data usage to this object.
                 combineValues(tmpEntry);
                 if (tag[i] == TAG_NONE) {
+                    // Add the migrated data to moved so it is deducted from the VPN app later.
                     moved[j].add(tmpEntry);
                     // Add debug info
                     tmpEntry.set = SET_DBG_VPN_IN;
@@ -1412,8 +1416,8 @@
             @NonNull String[] underlyingIfaces,
             @NonNull Entry[] moved) {
         for (int i = 0; i < underlyingIfaces.length; i++) {
-            // Add debug info
             moved[i].uid = tunUid;
+            // Add debug info
             moved[i].set = SET_DBG_VPN_OUT;
             moved[i].tag = TAG_NONE;
             moved[i].iface = underlyingIfaces[i];
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 1728d96..228e62d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -153,10 +153,9 @@
 
     /**
      * DNS resolver series jni method.
-     * Attempts to get netid of network which resolver will
-     * use if no network is explicitly selected.
+     * Attempts to get network which resolver will use if no network is explicitly selected.
      */
-    public static native int getDnsNetId() throws ErrnoException;
+    public static native Network getDnsNetwork() throws ErrnoException;
 
     /**
      * Get the tcp repair window associated with the {@code fd}.
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 00e0e3a..08aa1d9 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -304,13 +304,19 @@
     jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
 
-static jint android_net_utils_getDnsNetId(JNIEnv *env, jobject thiz) {
-    int dnsNetId = getNetworkForDns();
-    if (dnsNetId < 0) {
-        throwErrnoException(env, "getDnsNetId", -dnsNetId);
+static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
+    unsigned dnsNetId = 0;
+    if (int res = getNetworkForDns(&dnsNetId) < 0) {
+        throwErrnoException(env, "getDnsNetId", -res);
+        return nullptr;
     }
+    bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS;
 
-    return dnsNetId;
+    static jclass class_Network = MakeGlobalRefOrDie(
+            env, FindClassOrDie(env, "android/net/Network"));
+    static jmethodID ctor = env->GetMethodID(class_Network, "<init>", "(IZ)V");
+    return env->NewObject(
+            class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
 }
 
 static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
@@ -369,7 +375,7 @@
     { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
     { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
     { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
-    { "getDnsNetId", "()I", (void*) android_net_utils_getDnsNetId },
+    { "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 9488afb..3d5710d 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -484,7 +484,10 @@
             if (request.isForMainFrame()) {
                 mMainFrameUrl = request.getUrl().toString();
             }
-            return false;
+            // Be careful that two shouldOverrideUrlLoading methods are overridden, but
+            // shouldOverrideUrlLoading(WebView view, String url) was deprecated in API level 24.
+            // TODO: delete deprecated one ??
+            return shouldOverrideUrlLoading(view, mMainFrameUrl);
         }
 
         // A web page consisting of a large broken lock icon to indicate SSL failure.
diff --git a/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
index 4a02ee6..d06e5ec 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/BrushPropertyDrawable.kt
@@ -62,7 +62,7 @@
         return _size
     }
 
-    override fun draw(c: Canvas?) {
+    override fun draw(c: Canvas) {
         c?.let {
             val w = bounds.width().toFloat()
             val h = bounds.height().toFloat()
@@ -90,4 +90,4 @@
         //
     }
 
-}
\ No newline at end of file
+}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
index a4a3d3d..5431ae5 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -333,11 +333,11 @@
                             bits.width.toFloat()/oldBits.height,
                             bits.height.toFloat()/oldBits.width)
                 }
-                c.matrix = matrix
+                c.setMatrix(matrix)
             }
             // paint the old artwork atop the new
             c.drawBitmap(oldBits, 0f, 0f, _drawPaint)
-            c.matrix = Matrix()
+            c.setMatrix(Matrix())
         } else {
             c.drawColor(paperColor)
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4b2d481..f25bb59 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -169,6 +169,7 @@
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.connectivity.AutodestructReference;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
@@ -2761,29 +2762,31 @@
     }
 
     private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub {
-        private final NetworkAgentInfo mNai;
+        private final int mNetId;
+        private final AutodestructReference<NetworkAgentInfo> mNai;
 
         private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
-            mNai = nai;
+            mNetId = nai.network.netId;
+            mNai = new AutodestructReference(nai);
         }
 
         @Override
         public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
             mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT,
-                    new Pair<>(mNai, networkMonitor)));
+                    new Pair<>(mNai.getAndDestroy(), networkMonitor)));
         }
 
         @Override
         public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
             mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED,
-                    testResult, mNai.network.netId, redirectUrl));
+                    testResult, mNetId, redirectUrl));
         }
 
         @Override
         public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
             mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
                     EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
-                    0, mNai.network.netId, PrivateDnsConfig.fromParcel(config)));
+                    0, mNetId, PrivateDnsConfig.fromParcel(config)));
         }
 
         @Override
@@ -2801,15 +2804,13 @@
             }
             mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
                     EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW,
-                    mNai.network.netId,
-                    pendingIntent));
+                    mNetId, pendingIntent));
         }
 
         @Override
         public void hideProvisioningNotification() {
             mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
-                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
-                    mNai.network.netId));
+                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNetId));
         }
 
         @Override
@@ -4374,7 +4375,7 @@
         // the underlyingNetworks list.
         if (underlyingNetworks == null) {
             NetworkAgentInfo defaultNai = getDefaultNetwork();
-            if (defaultNai != null && defaultNai.linkProperties != null) {
+            if (defaultNai != null) {
                 underlyingNetworks = new Network[] { defaultNai.network };
             }
         }
@@ -4382,7 +4383,7 @@
             List<String> interfaces = new ArrayList<>();
             for (Network network : underlyingNetworks) {
                 LinkProperties lp = getLinkProperties(network);
-                if (lp != null) {
+                if (lp != null && !TextUtils.isEmpty(lp.getInterfaceName())) {
                     interfaces.add(lp.getInterfaceName());
                 }
             }
diff --git a/services/core/java/com/android/server/connectivity/AutodestructReference.java b/services/core/java/com/android/server/connectivity/AutodestructReference.java
new file mode 100644
index 0000000..009a43e
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/AutodestructReference.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A ref that autodestructs at the first usage of it.
+ * @param <T> The type of the held object
+ * @hide
+ */
+public class AutodestructReference<T> {
+    private final AtomicReference<T> mHeld;
+    public AutodestructReference(@NonNull T obj) {
+        if (null == obj) throw new NullPointerException("Autodestruct reference to null");
+        mHeld = new AtomicReference<>(obj);
+    }
+
+    /** Get the ref and destruct it. NPE if already destructed. */
+    @NonNull
+    public T getAndDestroy() {
+        final T obj = mHeld.getAndSet(null);
+        if (null == obj) throw new NullPointerException("Already autodestructed");
+        return obj;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0910dac2..f6735d9 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -237,9 +237,15 @@
                     + getTransportName(transportType));
             return;
         }
-
-        final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS :
-                SystemNotificationChannels.NETWORK_STATUS;
+        // When replacing an existing notification for a given network, don't alert, just silently
+        // update the existing notification. Note that setOnlyAlertOnce() will only work for the
+        // same id, and the id used here is the NotificationType which is different in every type of
+        // notification. This is required because the notification metrics only track the ID but not
+        // the tag.
+        final boolean hasPreviousNotification = previousNotifyType != null;
+        final String channelId = (highPriority && !hasPreviousNotification)
+                ? SystemNotificationChannels.NETWORK_ALERTS
+                : SystemNotificationChannels.NETWORK_STATUS;
         Notification.Builder builder = new Notification.Builder(mContext, channelId)
                 .setWhen(System.currentTimeMillis())
                 .setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index f5de2ad..e7a8b13 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -953,30 +953,22 @@
             return false;
         }
 
-        LinkProperties lp = makeLinkProperties();
-        final boolean hadInternetCapability = mNetworkCapabilities.hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        final boolean willHaveInternetCapability = providesRoutesToMostDestinations(lp);
-        if (hadInternetCapability != willHaveInternetCapability) {
-            // A seamless handover would have led to a change to INTERNET capability, which
-            // is supposed to be immutable for a given network. In this case bail out and do not
-            // perform handover.
-            Log.i(TAG, "Handover not possible due to changes to INTERNET capability");
-            return false;
-        }
-
-        agent.sendLinkProperties(lp);
+        agent.sendLinkProperties(makeLinkProperties());
         return true;
     }
 
     private void agentConnect() {
         LinkProperties lp = makeLinkProperties();
 
-        if (providesRoutesToMostDestinations(lp)) {
-            mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        } else {
-            mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        }
+        // VPN either provide a default route (IPv4 or IPv6 or both), or they are a split tunnel
+        // that falls back to the default network, which by definition provides INTERNET (unless
+        // there is no default network, in which case none of this matters in any sense).
+        // Also, always setting the INTERNET bit guarantees that when a VPN applies to an app,
+        // the VPN will always be reported as the network by getDefaultNetwork and callbacks
+        // registered with registerDefaultNetworkCallback. This in turn protects the invariant
+        // that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork())
+        // behaves the same as when it uses the default network.
+        mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
 
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index fde13ac..eb883c9 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -38,7 +38,6 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
-import android.util.ByteStringUtils;
 import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -52,6 +51,7 @@
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
+import libcore.util.HexEncoding;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -66,7 +66,6 @@
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -232,7 +231,7 @@
                                                 @UserIdInt int userId) {
         byte[] randomBytes = new byte[8];
         new SecureRandom().nextBytes(randomBytes);
-        String id = ByteStringUtils.toHexString(randomBytes).toLowerCase(Locale.US);
+        String id = HexEncoding.encodeToString(randomBytes, false /* upperCase */);
         File appDir = getInstantApplicationDir(packageName, userId);
         if (!appDir.exists() && !appDir.mkdirs()) {
             Slog.e(LOG_TAG, "Cannot create instant app cookie directory");
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java
index 88d9e52..9de6469 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DexLogger.java
@@ -16,12 +16,12 @@
 
 package com.android.server.pm.dex;
 
+import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.RemoteException;
-
 import android.util.ArraySet;
-import android.util.ByteStringUtils;
 import android.util.EventLog;
 import android.util.PackageUtils;
 import android.util.Slog;
@@ -31,11 +31,11 @@
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
 
+import libcore.util.HexEncoding;
+
 import java.io.File;
 import java.util.Set;
 
-import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
-
 /**
  * This class is responsible for logging data about secondary dex files.
  * The data logged includes hashes of the name and content of each file.
@@ -91,7 +91,7 @@
         String message = PackageUtils.computeSha256Digest(dexFileName.getBytes());
         // Valid SHA256 will be 256 bits, 32 bytes.
         if (hash.length == 32) {
-            message = message + ' ' + ByteStringUtils.toHexString(hash);
+            message = message + ' ' + HexEncoding.encodeToString(hash);
         }
 
         writeDclEvent(ownerUid, message);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 2cae250..ce50bef 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -727,94 +727,4 @@
                 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
                 "fe00::/8", "2605:ef80:e:af1d::/64");
     }
-
-    @Test
-    public void testProvidesRoutesToMostDestinations() {
-        final LinkProperties lp = new LinkProperties();
-
-        // Default route provides routes to all IPv4 destinations.
-        lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        // Empty LP provides routes to no destination
-        lp.clear();
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
-        // All IPv4 routes except for local networks. This is the case most relevant
-        // to this function. It provides routes to almost the entire space.
-        // (clone the stream so that we can reuse it later)
-        publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
-        // provide routes to "most" destinations.
-        lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        // Remove the /2 route, which represent a quarter of the available routing space.
-        // This LP does not provides routes to "most" destinations any more.
-        lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
-        lp.clear();
-        publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
-        // V6 does not provide sufficient coverage but v4 does
-        publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        // V4 still does
-        lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        // V4 does not any more
-        lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
-        // V4 does not, but V6 has sufficient coverage again
-        lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
-        lp.clear();
-        // V4-unreachable route should not be treated as sufficient coverage
-        lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
-        lp.clear();
-        // V6-unreachable route should not be treated as sufficient coverage
-        lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
-        assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-    }
-
-    @Test
-    public void testDoesNotLockUpWithTooManyRoutes() {
-        final LinkProperties lp = new LinkProperties();
-        final byte[] ad = new byte[4];
-        // Actually evaluating this many routes under 1500ms is impossible on
-        // current hardware and for some time, as the algorithm is O(n²).
-        // Make sure the system has a safeguard against this and does not
-        // lock up.
-        final int MAX_ROUTES = 4000;
-        final long MAX_ALLOWED_TIME_MS = 1500;
-        for (int i = 0; i < MAX_ROUTES; ++i) {
-            ad[0] = (byte)((i >> 24) & 0xFF);
-            ad[1] = (byte)((i >> 16) & 0xFF);
-            ad[2] = (byte)((i >> 8) & 0xFF);
-            ad[3] = (byte)(i & 0xFF);
-            try {
-                lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
-            } catch (UnknownHostException e) {
-                // UnknownHostException is only thrown for an address of illegal length,
-                // which can't happen in the case above.
-            }
-        }
-        final long start = SystemClock.currentThreadTimeMillis();
-        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-        final long end = SystemClock.currentThreadTimeMillis();
-        assertTrue(end - start < MAX_ALLOWED_TIME_MS);
-    }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 07b5ba4..31df9f3 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -61,7 +61,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -931,6 +930,65 @@
     }
 
     @Test
+    public void vpnRewriteTrafficThroughItself() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        //
+        // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+        // over VPN.
+        // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+        // over VPN.
+        //
+        // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic
+        // (100 bytes).
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 5)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L)
+                // VPN rewrites all the packets read from TUN + 100 additional bytes of VPN's
+                // own traffic.
+                .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 0L, 0L, 1600L, 160L, 2L)
+                // VPN sent 1760 bytes over WiFi in foreground (SET_FOREGROUND) i.e. 1600
+                // bytes (160 packets) + 1 byte/packet overhead (=160 bytes).
+                .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1760L, 176L, 1L)
+                // VPN received 3300 bytes over WiFi in background (SET_DEFAULT) i.e. 3000 bytes
+                // (300 packets) + 1 byte/packet encryption overhead (=300 bytes).
+                .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L));
+
+        forcePollAndWaitForIdle();
+
+        // Verify increased TUN usage by UID_VPN does not get attributed to other apps.
+        NetworkStats tunStats =
+                mService.getDetailedUidStats(new String[] {TUN_IFACE});
+        assertValues(
+                tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 1);
+        assertValues(
+                tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 1);
+        assertValues(
+                tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+                DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 2);
+
+        // Verify correct attribution over WiFi.
+        assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 260L, 26L, 2);
+    }
+
+    @Test
     public void vpnWithOneUnderlyingIface() throws Exception {
         // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
         expectDefaultSettings();
@@ -946,25 +1004,74 @@
                 getActiveIface(networkStates));
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
-        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
-        // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
-        // VPN sent/received 1650 bytes (150 packets) over WiFi.
-        // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
-        // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
+        // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+        // over VPN.
+        // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+        // over VPN.
+        // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi.
+        // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
+        // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
+        // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
+        // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
-                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
-                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
-                // VPN received 1650 bytes over WiFi in background (SET_DEFAULT).
-                .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L)
+                // VPN received 3300 bytes over WiFi in background (SET_DEFAULT).
+                .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L)
                 // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND).
                 .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L));
 
         forcePollAndWaitForIdle();
 
-        assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
-        assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
-        assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
+        assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 150L, 0L, 2);
+    }
+
+    @Test
+    public void vpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+        // over VPN.
+        // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+        // over VPN.
+        // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun
+        // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500
+        // packets) from it. Including overhead that is 6600/5500 bytes.
+        // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi.
+        // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
+        // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN.
+        // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
+        // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L)
+                .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 5000L, 500L, 6000L, 600L, 1L)
+                // VPN received 8800 bytes over WiFi in background (SET_DEFAULT).
+                .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 8800L, 800L, 0L, 0L, 1L)
+                // VPN sent 8250 bytes over WiFi in foreground (SET_FOREGROUND).
+                .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 8250L, 750L, 1L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 5800L, 500L, 6750L, 600L, 2);
     }
 
     @Test
@@ -1068,24 +1175,28 @@
                 getActiveIface(networkStates));
         // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
         // overhead per packet):
-        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
-        // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
-        // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both
-        // rx/tx.
-        // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx.
+        // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over
+        // VPN.
+        // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
+        // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell.
+        // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx)
+        // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell.
+        //
+        // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic.
+        // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic.
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
-              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L)
-              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L)
-              .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L));
+              .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 500L, 50L, 1000L, 100L, 2L)
+              .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 330L, 30L, 660L, 60L, 1L)
+              .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 220L, 20L, 440L, 40L, 1L));
 
         forcePollAndWaitForIdle();
 
-        assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1);
-        assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1);
+        assertUidTotal(sTemplateWifi, UID_RED, 300L, 30L, 600L, 60L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 30L, 0L, 60L, 0L, 1);
 
-        assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1);
-        assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 400L, 40L, 1);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 20L, 0L, 40L, 0L, 1);
     }
 
     @Test