Merge "Add another OptionsBuilder constructor with the source type as one of its parameter."
diff --git a/boot/Android.bp b/boot/Android.bp
index 3caede4..09cd0d4 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -52,9 +52,45 @@
             module: "art-bootclasspath-fragment",
         },
         {
+            apex: "com.android.conscrypt",
+            module: "com.android.conscrypt-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.i18n",
             module: "i18n-bootclasspath-fragment",
         },
+        {
+            apex: "com.android.ipsec",
+            module: "com.android.ipsec-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.media",
+            module: "com.android.media-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.mediaprovider",
+            module: "com.android.mediaprovider-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.os.statsd",
+            module: "com.android.os.statsd-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.permission",
+            module: "com.android.permission-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.sdkext",
+            module: "com.android.sdkext-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.tethering",
+            module: "com.android.tethering-bootclasspath-fragment",
+        },
+        {
+            apex: "com.android.wifi",
+            module: "com.android.wifi-bootclasspath-fragment",
+        },
     ],
 
     // Additional information needed by hidden api processing.
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index cc1312b..b18e9be 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -16,6 +16,16 @@
 
 package android.net;
 
+import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
+import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
+
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.util.Preconditions.checkStringNotEmpty;
 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
@@ -70,13 +80,28 @@
     private static final String EMPTY_CERT = "";
 
     /** @hide */
-    public static final List<String> DEFAULT_ALGORITHMS =
-            Collections.unmodifiableList(Arrays.asList(
-                    IpSecAlgorithm.CRYPT_AES_CBC,
-                    IpSecAlgorithm.AUTH_HMAC_SHA256,
-                    IpSecAlgorithm.AUTH_HMAC_SHA384,
-                    IpSecAlgorithm.AUTH_HMAC_SHA512,
-                    IpSecAlgorithm.AUTH_CRYPT_AES_GCM));
+    public static final List<String> DEFAULT_ALGORITHMS;
+
+    private static void addAlgorithmIfSupported(List<String> algorithms, String ipSecAlgoName) {
+        if (IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName)) {
+            algorithms.add(ipSecAlgoName);
+        }
+    }
+
+    static {
+        final List<String> algorithms = new ArrayList<>();
+        addAlgorithmIfSupported(algorithms, CRYPT_AES_CBC);
+        addAlgorithmIfSupported(algorithms, CRYPT_AES_CTR);
+        addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA256);
+        addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA384);
+        addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA512);
+        addAlgorithmIfSupported(algorithms, AUTH_AES_XCBC);
+        addAlgorithmIfSupported(algorithms, AUTH_AES_CMAC);
+        addAlgorithmIfSupported(algorithms, AUTH_CRYPT_AES_GCM);
+        addAlgorithmIfSupported(algorithms, AUTH_CRYPT_CHACHA20_POLY1305);
+
+        DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms);
+    }
 
     @NonNull private final String mServerAddr;
     @NonNull private final String mUserIdentity;
@@ -195,8 +220,6 @@
      * @param allowedAlgorithms The list to be validated
      */
     private static void validateAllowedAlgorithms(@NonNull List<String> algorithmNames) {
-        VpnProfile.validateAllowedAlgorithms(algorithmNames);
-
         // First, make sure no insecure algorithms were proposed.
         if (algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_MD5)
                 || algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA1)) {
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index b7170d8..6e1d3ce 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -30,7 +30,10 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.ProxyUtils;
 
+import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -74,6 +77,9 @@
 
     private static final String ENCODED_NULL_PROXY_INFO = "\0\0\0\0";
 
+    /** Default URL encoding. */
+    private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
+
     // Entity fields.
     @UnsupportedAppUsage
     public final String key;                                   // -1
@@ -129,9 +135,6 @@
 
     /**
      * The list of allowable algorithms.
-     *
-     * <p>This list is validated in the setter to ensure that encoding characters (list, value
-     * delimiters) are not present in the algorithm names. See {@link #validateAllowedAlgorithms()}
      */
     private List<String> mAllowedAlgorithms = new ArrayList<>(); // 19
     public boolean isBypassable = false;                         // 20
@@ -196,11 +199,8 @@
      *
      * @param allowedAlgorithms the list of allowable algorithms, as listed in {@link
      *     IpSecAlgorithm}.
-     * @throws IllegalArgumentException if any delimiters are used in algorithm names. See {@link
-     *     #VALUE_DELIMITER} and {@link LIST_DELIMITER}.
      */
     public void setAllowedAlgorithms(List<String> allowedAlgorithms) {
-        validateAllowedAlgorithms(allowedAlgorithms);
         mAllowedAlgorithms = allowedAlgorithms;
     }
 
@@ -297,7 +297,11 @@
 
             // Either all must be present, or none must be.
             if (values.length >= 24) {
-                profile.mAllowedAlgorithms = Arrays.asList(values[19].split(LIST_DELIMITER));
+                profile.mAllowedAlgorithms = new ArrayList<>();
+                for (String algo : Arrays.asList(values[19].split(LIST_DELIMITER))) {
+                    profile.mAllowedAlgorithms.add(URLDecoder.decode(algo, DEFAULT_ENCODING));
+                }
+
                 profile.isBypassable = Boolean.parseBoolean(values[20]);
                 profile.isMetered = Boolean.parseBoolean(values[21]);
                 profile.maxMtu = Integer.parseInt(values[22]);
@@ -348,7 +352,19 @@
             builder.append(ENCODED_NULL_PROXY_INFO);
         }
 
-        builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, mAllowedAlgorithms));
+        final List<String> encodedAlgoNames = new ArrayList<>();
+
+        try {
+            for (String algo : mAllowedAlgorithms) {
+                encodedAlgoNames.add(URLEncoder.encode(algo, DEFAULT_ENCODING));
+            }
+        } catch (UnsupportedEncodingException e) {
+            // Unexpected error
+            throw new IllegalStateException("Failed to encode algorithms.", e);
+        }
+
+        builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, encodedAlgoNames));
+
         builder.append(VALUE_DELIMITER).append(isBypassable);
         builder.append(VALUE_DELIMITER).append(isMetered);
         builder.append(VALUE_DELIMITER).append(maxMtu);
@@ -425,20 +441,6 @@
         return true;
     }
 
-    /**
-     * Validates that the provided list of algorithms does not contain illegal characters.
-     *
-     * @param allowedAlgorithms The list to be validated
-     */
-    public static void validateAllowedAlgorithms(List<String> allowedAlgorithms) {
-        for (final String alg : allowedAlgorithms) {
-            if (alg.contains(VALUE_DELIMITER) || alg.contains(LIST_DELIMITER)) {
-                throw new IllegalArgumentException(
-                        "Algorithm contained illegal ('\0' or ',') character");
-            }
-        }
-    }
-
     /** Generates a hashcode over the VpnProfile. */
     @Override
     public int hashCode() {
diff --git a/core/java/com/android/internal/os/BinderDeathDispatcher.java b/core/java/com/android/internal/os/BinderDeathDispatcher.java
index 0c93f7f..038707e 100644
--- a/core/java/com/android/internal/os/BinderDeathDispatcher.java
+++ b/core/java/com/android/internal/os/BinderDeathDispatcher.java
@@ -63,6 +63,10 @@
 
         @Override
         public void binderDied() {
+        }
+
+        @Override
+        public void binderDied(IBinder who) {
             final ArraySet<DeathRecipient> copy;
             synchronized (mLock) {
                 copy = mRecipients;
@@ -77,7 +81,7 @@
             // Let's call it without holding the lock.
             final int size = copy.size();
             for (int i = 0; i < size; i++) {
-                copy.valueAt(i).binderDied();
+                copy.valueAt(i).binderDied(who);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java
index 59cc66d..4ca59be 100644
--- a/core/java/com/android/internal/os/BinderLatencyObserver.java
+++ b/core/java/com/android/internal/os/BinderLatencyObserver.java
@@ -16,22 +16,37 @@
 
 package com.android.internal.os;
 
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
 import android.annotation.Nullable;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemClock;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BinderInternal.CallSession;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
+import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.Random;
 
 /** Collects statistics about Binder call latency per calling API and method. */
 public class BinderLatencyObserver {
     private static final String TAG = "BinderLatencyObserver";
+    private static final int MAX_ATOM_SIZE_BYTES = 4064;
+    // Be conservative and leave 1K space for the last histogram so we don't go over the size limit.
+    private static final int LAST_HISTOGRAM_BUFFER_SIZE_BYTES = 1000;
+
+    // Latency observer parameters.
     public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10;
+    public static final int STATSD_PUSH_INTERVAL_MINUTES_DEFAULT = 360;
 
     // Histogram buckets parameters.
     public static final int BUCKET_COUNT_DEFAULT = 100;
@@ -50,20 +65,124 @@
     private int mFirstBucketSize = FIRST_BUCKET_SIZE_DEFAULT;
     private float mBucketScaleFactor = BUCKET_SCALE_FACTOR_DEFAULT;
 
+    private int mStatsdPushIntervalMinutes = STATSD_PUSH_INTERVAL_MINUTES_DEFAULT;
+
     private final Random mRandom;
     private BinderLatencyBuckets mLatencyBuckets;
 
+    private final Handler mLatencyObserverHandler;
+
+    private Runnable mLatencyObserverRunnable = new Runnable() {
+        @Override
+        public void run() {
+            // Schedule the next push.
+            noteLatencyDelayed();
+
+            ArrayMap<LatencyDims, int[]> histogramMap;
+            synchronized (mLock) {
+                // Copy the histograms map so we don't use the lock for longer than needed.
+                histogramMap = new ArrayMap<>(mLatencyHistograms);
+                mLatencyHistograms.clear();
+            }
+
+            BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+            ProtoOutputStream proto = new ProtoOutputStream();
+            int histogramsWritten = 0;
+
+            for (LatencyDims dims : histogramMap.keySet()) {
+                // Start a new atom if the next histogram risks going over the atom size limit.
+                if (proto.getRawSize() + LAST_HISTOGRAM_BUFFER_SIZE_BYTES > getMaxAtomSizeBytes()) {
+                    if (histogramsWritten > 0) {
+                        writeAtomToStatsd(proto);
+                    }
+                    proto = new ProtoOutputStream();
+                    histogramsWritten = 0;
+                }
+
+                String transactionName = resolver.getMethodName(
+                        dims.getBinderClass(), dims.getTransactionCode());
+                fillApiStatsProto(proto, dims, transactionName, histogramMap.get(dims));
+                histogramsWritten++;
+            }
+            // Push the final atom.
+            if (histogramsWritten > 0) {
+                writeAtomToStatsd(proto);
+            }
+        }
+    };
+
+    private void fillApiStatsProto(
+            ProtoOutputStream proto, LatencyDims dims, String transactionName, int[] histogram) {
+        // Find the part of the histogram to write.
+        int firstNonEmptyBucket = 0;
+        for (int i = 0; i < mBucketCount; i++) {
+            if (histogram[i] != 0) {
+                firstNonEmptyBucket = i;
+                break;
+            }
+        }
+        int lastNonEmptyBucket = mBucketCount - 1;
+        for (int i = mBucketCount - 1; i >= 0; i--) {
+            if (histogram[i] != 0) {
+                lastNonEmptyBucket = i;
+                break;
+            }
+        }
+
+        // Start a new ApiStats proto.
+        long apiStatsToken = proto.start(RepeatedApiStats.API_STATS);
+
+        // Write the dims.
+        long dimsToken = proto.start(ApiStats.DIMS);
+        proto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+        proto.write(Dims.SERVICE_CLASS_NAME, dims.getBinderClass().getName());
+        proto.write(Dims.SERVICE_METHOD_NAME, transactionName);
+        proto.end(dimsToken);
+
+        // Write the histogram.
+        proto.write(ApiStats.FIRST_BUCKET_INDEX, firstNonEmptyBucket);
+        for (int i = firstNonEmptyBucket; i <= lastNonEmptyBucket; i++) {
+            proto.write(ApiStats.BUCKETS, histogram[i]);
+        }
+
+        proto.end(apiStatsToken);
+    }
+
+    protected int getMaxAtomSizeBytes() {
+        return MAX_ATOM_SIZE_BYTES;
+    }
+
+    protected void writeAtomToStatsd(ProtoOutputStream atom) {
+        FrameworkStatsLog.write(
+                FrameworkStatsLog.BINDER_LATENCY_REPORTED,
+                atom.getBytes(),
+                mPeriodicSamplingInterval,
+                1);
+    }
+
+    private void noteLatencyDelayed() {
+        mLatencyObserverHandler.removeCallbacks(mLatencyObserverRunnable);
+        mLatencyObserverHandler.postDelayed(mLatencyObserverRunnable,
+                mStatsdPushIntervalMinutes * 60 * 1000);
+    }
+
     /** Injector for {@link BinderLatencyObserver}. */
     public static class Injector {
         public Random getRandomGenerator() {
             return new Random();
         }
+
+        public Handler getHandler() {
+            return new Handler(Looper.getMainLooper());
+        }
     }
 
     public BinderLatencyObserver(Injector injector) {
         mRandom = injector.getRandomGenerator();
+        mLatencyObserverHandler = injector.getHandler();
         mLatencyBuckets = new BinderLatencyBuckets(
             mBucketCount, mFirstBucketSize, mBucketScaleFactor);
+        noteLatencyDelayed();
     }
 
     /** Should be called when a Binder call completes, will store latency data. */
@@ -73,7 +192,8 @@
         }
 
         LatencyDims dims = new LatencyDims(s.binderClass, s.transactionCode);
-        long callDuration = getElapsedRealtimeMicro() - s.timeStarted;
+        long elapsedTimeMicro = getElapsedRealtimeMicro();
+        long callDuration = elapsedTimeMicro - s.timeStarted;
 
         // Find the bucket this sample should go to.
         int bucketIdx = mLatencyBuckets.sampleToBucket(
@@ -117,6 +237,22 @@
         }
     }
 
+    /** Updates the statsd push interval. */
+    public void setPushInterval(int pushIntervalMinutes) {
+        if (pushIntervalMinutes <= 0) {
+            Slog.w(TAG, "Ignored invalid push interval (value must be positive): "
+                    + pushIntervalMinutes);
+            return;
+        }
+
+        synchronized (mLock) {
+            if (pushIntervalMinutes != mStatsdPushIntervalMinutes) {
+                mStatsdPushIntervalMinutes = pushIntervalMinutes;
+                reset();
+            }
+        }
+    }
+
     /** Updates the histogram buckets parameters. */
     public void setHistogramBucketsParams(
             int bucketCount, int firstBucketSize, float bucketScaleFactor) {
@@ -138,6 +274,7 @@
         synchronized (mLock) {
             mLatencyHistograms.clear();
         }
+        noteLatencyDelayed();
     }
 
     /** Container for binder latency information. */
@@ -187,4 +324,9 @@
     public ArrayMap<LatencyDims, int[]> getLatencyHistograms() {
         return mLatencyHistograms;
     }
+
+    @VisibleForTesting
+    public Runnable getStatsdPushRunnable() {
+        return mLatencyObserverRunnable;
+    }
 }
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index f44b9fb..fdc3a9ee 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -1,6 +1,16 @@
 {
   "presubmit": [
     {
+      "file_patterns": [
+        "BinderDeathDispatcher\\.java"
+      ],
+      "name": "FrameworksCoreTests",
+      "options": [
+        { "include-filter": "com.android.internal.os.BinderDeathDispatcherTest" },
+        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+      ]
+    },
+    {
       "name": "FrameworksCoreTests",
       "options": [
         {
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
index 980e12d..83e2f2b 100644
--- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -31,7 +31,7 @@
 }
 
 static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
-    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
+    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFd(env, javaFd));
 }
 
 static const JNINativeMethod gNetworkUtilMethods[] = {
diff --git a/core/proto/android/internal/binder_latency.proto b/core/proto/android/internal/binder_latency.proto
new file mode 100644
index 0000000..e32c3e3
--- /dev/null
+++ b/core/proto/android/internal/binder_latency.proto
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+syntax = "proto2";
+package com.android.internal.os;
+
+option java_outer_classname = "BinderLatencyProto";
+
+/**
+ * RepeatedApiStats proto from atoms.proto, duplicated here so that it's
+ * accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message RepeatedApiStats {
+  repeated ApiStats api_stats = 1;
+}
+
+message Dims {
+  enum ProcessSource {
+    UNKNOWN_PROCESS_SOURCE = 0;
+    SYSTEM_SERVER = 1;
+    TELEPHONY = 2;
+  }
+
+  enum ServiceClassName {
+    UNKNOWN_CLASS = 0;
+  }
+  enum ServiceMethodName {
+    UNKNOWN_METHOD = 0;
+  }
+
+  // Required.
+  optional ProcessSource process_source = 1;
+
+  // The class name of the API making the call to Binder. Enum value
+  // is preferred as uses much less data to store.
+  // This field does not contain PII.
+  oneof service_class {
+    ServiceClassName service_class_name_as_enum = 2;
+    string service_class_name = 3;
+  }
+
+  // Method name of the API call. It can also be a transaction code if we
+  // cannot resolve it to a name. See Binder#getTransactionName. Enum value
+  // is preferred as uses much less data to store.
+  // This field does not contain PII.
+  oneof service_method {
+    ServiceMethodName service_method_name_as_enum = 4;
+    string service_method_name = 5;
+  }
+}
+
+message ApiStats {
+  // required.
+  optional Dims dims = 1;
+
+  // Indicates the first bucket that had any data. Allows omitting any empty
+  // buckets at the start of the bucket list and thus save on data size.
+  optional int32 first_bucket_index = 2;
+  // Stores the count of samples for each bucket. The number of buckets and
+  // their sizes are controlled server side with a flag.
+  repeated int32 buckets = 3;
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 942045c..8310333 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -17,6 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -31,14 +32,14 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.FileDescriptor;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BinderDeathDispatcherTest {
@@ -120,7 +121,7 @@
         public void die() {
             isAlive = false;
             if (mRecipient != null) {
-                mRecipient.binderDied();
+                mRecipient.binderDied(this);
             }
             mRecipient = null;
         }
@@ -227,33 +228,33 @@
         // Kill the targets.
 
         t1.die();
-        verify(r1, times(1)).binderDied();
-        verify(r2, times(1)).binderDied();
-        verify(r3, times(1)).binderDied();
-        verify(r4, times(0)).binderDied();
-        verify(r5, times(0)).binderDied();
+        verify(r1, times(1)).binderDied(t1);
+        verify(r2, times(1)).binderDied(t1);
+        verify(r3, times(1)).binderDied(t1);
+        verify(r4, times(0)).binderDied(any());
+        verify(r5, times(0)).binderDied(any());
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(2);
 
         reset(r1, r2, r3, r4, r5);
 
         t2.die();
-        verify(r1, times(1)).binderDied();
-        verify(r2, times(0)).binderDied();
-        verify(r3, times(0)).binderDied();
-        verify(r4, times(0)).binderDied();
-        verify(r5, times(0)).binderDied();
+        verify(r1, times(1)).binderDied(t2);
+        verify(r2, times(0)).binderDied(any());
+        verify(r3, times(0)).binderDied(any());
+        verify(r4, times(0)).binderDied(any());
+        verify(r5, times(0)).binderDied(any());
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
 
         reset(r1, r2, r3, r4, r5);
 
         t3.die();
-        verify(r1, times(0)).binderDied();
-        verify(r2, times(0)).binderDied();
-        verify(r3, times(1)).binderDied();
-        verify(r4, times(0)).binderDied();
-        verify(r5, times(1)).binderDied();
+        verify(r1, times(0)).binderDied(any());
+        verify(r2, times(0)).binderDied(any());
+        verify(r3, times(1)).binderDied(t3);
+        verify(r4, times(0)).binderDied(any());
+        verify(r5, times(1)).binderDied(t3);
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
 
@@ -262,4 +263,27 @@
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
     }
+
+    @Test
+    public void duplicateRegistrations() {
+        BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
+
+        MyTarget t1 = new MyTarget();
+
+        DeathRecipient r1 = mock(DeathRecipient.class);
+        DeathRecipient r2 = mock(DeathRecipient.class);
+
+        for (int i = 0; i < 5; i++) {
+            assertThat(d.linkToDeath(t1, r1)).isEqualTo(1);
+        }
+        assertThat(d.linkToDeath(t1, r2)).isEqualTo(2);
+
+        t1.die();
+        verify(r1, times(1)).binderDied(t1);
+        verify(r2, times(1)).binderDied(t1);
+
+        d.unlinkToDeath(t1, r1);
+        d.unlinkToDeath(t1, r2);
+        assertThat(d.getTargetsForTest()).isEmpty();
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
index f65fb95..bf87683 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.os;
 
+import static com.android.internal.os.BinderLatencyProto.Dims.SYSTEM_SERVER;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -23,16 +25,21 @@
 import android.os.Binder;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.BinderInternal.CallSession;
 import com.android.internal.os.BinderLatencyObserver.LatencyDims;
+import com.android.internal.os.BinderLatencyProto.ApiStats;
+import com.android.internal.os.BinderLatencyProto.Dims;
+import com.android.internal.os.BinderLatencyProto.RepeatedApiStats;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Random;
 
@@ -49,11 +56,17 @@
         CallSession callSession = new CallSession();
         callSession.binderClass = binder.getClass();
         callSession.transactionCode = 1;
+
+        blo.setElapsedTime(2);
         blo.callEnded(callSession);
+        blo.setElapsedTime(4);
         blo.callEnded(callSession);
+        blo.setElapsedTime(6);
         blo.callEnded(callSession);
         callSession.transactionCode = 2;
+        blo.setElapsedTime(8);
         blo.callEnded(callSession);
+        blo.setElapsedTime(10);
         blo.callEnded(callSession);
 
         ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -74,8 +87,10 @@
         CallSession callSession = new CallSession();
         callSession.binderClass = binder.getClass();
         callSession.transactionCode = 1;
+        blo.setElapsedTime(2);
         blo.callEnded(callSession);
         callSession.transactionCode = 2;
+        blo.setElapsedTime(4);
         blo.callEnded(callSession);
 
         ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms();
@@ -89,13 +104,13 @@
     @Test
     public void testTooCallLengthOverflow() {
         TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
-        blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
         blo.setHistogramBucketsParams(5, 5, 1.125f);
 
         Binder binder = new Binder();
         CallSession callSession = new CallSession();
         callSession.binderClass = binder.getClass();
         callSession.transactionCode = 1;
+        blo.setElapsedTime(2L + (long) Integer.MAX_VALUE);
         blo.callEnded(callSession);
 
         // The long call should be capped to maxint (to not overflow) and placed in the last bucket.
@@ -114,6 +129,7 @@
         CallSession callSession = new CallSession();
         callSession.binderClass = binder.getClass();
         callSession.transactionCode = 1;
+        blo.setElapsedTime(2);
         blo.callEnded(callSession);
 
         LatencyDims dims = new LatencyDims(binder.getClass(), 1);
@@ -122,14 +138,111 @@
         assertThat(blo.getLatencyHistograms().get(dims))
             .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
         // Try to add another sample.
+        blo.setElapsedTime(2);
         blo.callEnded(callSession);
         // Make sure the buckets don't overflow.
         assertThat(blo.getLatencyHistograms().get(dims))
             .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
     }
 
+    @Test
+    public void testSingleAtomPush() {
+        TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+        Binder binder = new Binder();
+        CallSession callSession = new CallSession();
+        callSession.binderClass = binder.getClass();
+        callSession.transactionCode = 1;
+        blo.setElapsedTime(7);
+        blo.callEnded(callSession);
+        blo.callEnded(callSession);
+        blo.setElapsedTime(8);
+        blo.callEnded(callSession);
+
+        // Trigger the statsd push.
+        blo.getStatsdPushRunnable().run();
+
+        ProtoOutputStream expectedProto = new ProtoOutputStream();
+        long apiStatsToken = expectedProto.start(RepeatedApiStats.API_STATS);
+        long dimsToken = expectedProto.start(ApiStats.DIMS);
+        expectedProto.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+        expectedProto.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+        expectedProto.write(Dims.SERVICE_METHOD_NAME, "1");
+        expectedProto.end(dimsToken);
+        expectedProto.write(ApiStats.FIRST_BUCKET_INDEX, 3);
+        expectedProto.write(ApiStats.BUCKETS, 2);
+        expectedProto.write(ApiStats.BUCKETS, 1);
+        expectedProto.end(apiStatsToken);
+
+        assertThat(blo.getWrittenAtoms())
+                .containsExactly(Arrays.toString(expectedProto.getBytes()));
+    }
+
+    @Test
+    public void testMultipleAtomPush() {
+        TestBinderLatencyObserver blo = new TestBinderLatencyObserver();
+
+        BinderTransactionNameResolver resolver = new BinderTransactionNameResolver();
+
+
+        Binder binder = new Binder();
+        CallSession callSession = new CallSession();
+        callSession.binderClass = binder.getClass();
+        callSession.transactionCode = 1;
+        blo.setElapsedTime(1);
+        blo.callEnded(callSession);
+        callSession.transactionCode = 2;
+        blo.setElapsedTime(5);
+        blo.callEnded(callSession);
+        callSession.transactionCode = 3;
+        blo.callEnded(callSession);
+
+        // Trigger the statsd push.
+        blo.getStatsdPushRunnable().run();
+
+        ProtoOutputStream expectedProto1 = new ProtoOutputStream();
+        long apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+        long dimsToken = expectedProto1.start(ApiStats.DIMS);
+        expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+        expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+        expectedProto1.write(Dims.SERVICE_METHOD_NAME, "1");
+        expectedProto1.end(dimsToken);
+        expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 0);
+        expectedProto1.write(ApiStats.BUCKETS, 1);
+        expectedProto1.end(apiStatsToken);
+
+        apiStatsToken = expectedProto1.start(RepeatedApiStats.API_STATS);
+        dimsToken = expectedProto1.start(ApiStats.DIMS);
+        expectedProto1.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+        expectedProto1.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+        expectedProto1.write(Dims.SERVICE_METHOD_NAME, "2");
+        expectedProto1.end(dimsToken);
+        expectedProto1.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+        expectedProto1.write(ApiStats.BUCKETS, 1);
+        expectedProto1.end(apiStatsToken);
+
+        ProtoOutputStream expectedProto2 = new ProtoOutputStream();
+        apiStatsToken = expectedProto2.start(RepeatedApiStats.API_STATS);
+        dimsToken = expectedProto2.start(ApiStats.DIMS);
+        expectedProto2.write(Dims.PROCESS_SOURCE, SYSTEM_SERVER);
+        expectedProto2.write(Dims.SERVICE_CLASS_NAME, binder.getClass().getName());
+        expectedProto2.write(Dims.SERVICE_METHOD_NAME, "3");
+        expectedProto2.end(dimsToken);
+        expectedProto2.write(ApiStats.FIRST_BUCKET_INDEX, 1);
+        expectedProto2.write(ApiStats.BUCKETS, 1);
+        expectedProto2.end(apiStatsToken);
+
+        // Each ApiStats is around ~60 bytes so only two should fit in an atom.
+        assertThat(blo.getWrittenAtoms())
+                .containsExactly(
+                        Arrays.toString(expectedProto1.getBytes()),
+                        Arrays.toString(expectedProto2.getBytes()))
+                .inOrder();
+    }
+
     public static class TestBinderLatencyObserver extends BinderLatencyObserver {
         private long mElapsedTime = 0;
+        private ArrayList<String> mWrittenAtoms;
 
         TestBinderLatencyObserver() {
             // Make random generator not random.
@@ -145,16 +258,30 @@
                 }
             });
             setSamplingInterval(1);
+            mWrittenAtoms = new ArrayList<>();
         }
 
         @Override
         protected long getElapsedRealtimeMicro() {
-            mElapsedTime += 2;
             return mElapsedTime;
         }
 
+        @Override
+        protected int getMaxAtomSizeBytes() {
+            return 1100;
+        }
+
+        @Override
+        protected void writeAtomToStatsd(ProtoOutputStream atom) {
+            mWrittenAtoms.add(Arrays.toString(atom.getBytes()));
+        }
+
         public void setElapsedTime(long time) {
             mElapsedTime = time;
         }
+
+        public ArrayList<String> getWrittenAtoms() {
+            return mWrittenAtoms;
+        }
     }
 }
diff --git a/packages/Connectivity/OWNERS b/packages/Connectivity/OWNERS
index 48e54da..4f1e3e5 100644
--- a/packages/Connectivity/OWNERS
+++ b/packages/Connectivity/OWNERS
@@ -1,3 +1,3 @@
-set noparent
-
-include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
+# Placing an OWNERS block to perform migration
+# detailed in b/186628461
+baligh@google.com
diff --git a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
index 48e262a..f17baf9 100644
--- a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
+++ b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
@@ -76,7 +76,7 @@
         filter_code,
     };
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
                 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -86,7 +86,7 @@
 static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     int optval_ignored = 0;
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
         0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
@@ -112,7 +112,7 @@
 
 static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jobject javaFd,
                                                   jint netId) {
-    return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
+    return setNetworkForSocket(netId, AFileDescriptor_getFd(env, javaFd));
 }
 
 static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
@@ -160,7 +160,7 @@
 }
 
 static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     int rcode;
     std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
 
@@ -187,7 +187,7 @@
 }
 
 static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     resNetworkCancel(fd);
     jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
@@ -213,7 +213,7 @@
         return NULL;
     }
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     struct tcp_repair_window trw = {};
     socklen_t size = sizeof(trw);
 
diff --git a/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java
index 1abd39a..0707ef3 100644
--- a/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java
+++ b/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java
@@ -29,8 +29,8 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.net.VpnProfile;
-import com.android.net.module.util.ProxyUtils;
 import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
+import com.android.net.module.util.ProxyUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -170,7 +170,10 @@
         final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
         builder.setAuthPsk(PSK_BYTES);
 
-        List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
+        List<String> allowedAlgorithms =
+                Arrays.asList(
+                        IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                        IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305);
         builder.setAllowedAlgorithms(allowedAlgorithms);
 
         final Ikev2VpnProfile profile = builder.build();
@@ -183,7 +186,12 @@
         builder.setAuthPsk(PSK_BYTES);
 
         List<String> allowedAlgorithms =
-                Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
+                Arrays.asList(
+                        IpSecAlgorithm.AUTH_HMAC_SHA512,
+                        IpSecAlgorithm.AUTH_AES_XCBC,
+                        IpSecAlgorithm.AUTH_AES_CMAC,
+                        IpSecAlgorithm.CRYPT_AES_CBC,
+                        IpSecAlgorithm.CRYPT_AES_CTR);
         builder.setAllowedAlgorithms(allowedAlgorithms);
 
         final Ikev2VpnProfile profile = builder.build();
diff --git a/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java
index 46597d1..cb0f071 100644
--- a/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java
+++ b/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java
@@ -23,7 +23,6 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.net.IpSecAlgorithm;
 
@@ -97,6 +96,7 @@
         p.setAllowedAlgorithms(
                 Arrays.asList(
                         IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                        IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305,
                         IpSecAlgorithm.AUTH_HMAC_SHA512,
                         IpSecAlgorithm.CRYPT_AES_CBC));
         p.isBypassable = true;
@@ -126,30 +126,6 @@
     }
 
     @Test
-    public void testSetInvalidAlgorithmValueDelimiter() {
-        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
-        try {
-            profile.setAllowedAlgorithms(
-                    Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
-            fail("Expected failure due to value separator in algorithm name");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testSetInvalidAlgorithmListDelimiter() {
-        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
-        try {
-            profile.setAllowedAlgorithms(
-                    Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
-            fail("Expected failure due to value separator in algorithm name");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
     public void testEncodeDecode() {
         final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
         final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7cdcc01..781c354 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -91,6 +91,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BinderDeathDispatcher;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -176,6 +177,8 @@
                     .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                             | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
 
+    private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher =
+            new BinderDeathDispatcher<>();
     final LocalLog mLog = new LocalLog(TAG);
 
     AppOpsManager mAppOps;
@@ -1701,9 +1704,8 @@
         }
 
         if (directReceiver != null) {
-            try {
-                directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0);
-            } catch (RemoteException e) {
+            if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient)
+                    <= 0) {
                 Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag);
                 return;
             }
@@ -2464,6 +2466,10 @@
             pw.println("]");
             pw.println();
 
+            pw.println("Listener death dispatcher state:");
+            sListenerDeathDispatcher.dump(pw, "  ");
+            pw.println();
+
             if (mLog.dump(pw, "  Recent problems", "    ")) {
                 pw.println();
             }
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 339ca84..65bb21c 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -134,6 +134,8 @@
         private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data";
         private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
                 "latency_observer_sampling_interval";
+        private static final String SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY =
+                "latency_observer_push_interval_minutes";
         private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY =
                 "latency_histogram_bucket_count";
         private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY =
@@ -211,7 +213,9 @@
                     mParser.getFloat(
                         SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY,
                         BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT));
-
+            binderLatencyObserver.setPushInterval(mParser.getInt(
+                    SETTINGS_LATENCY_OBSERVER_PUSH_INTERVAL_MINUTES_KEY,
+                    BinderLatencyObserver.STATSD_PUSH_INTERVAL_MINUTES_DEFAULT));
 
             final boolean enabled =
                     mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5122be2..011a356 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4060,13 +4060,19 @@
 
         final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64);
         final long now = System.currentTimeMillis();
-        Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
-        for (int i = 0; i < files.length; ++i) {
-            if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) {
-                if (!files[i].delete()) {
-                    Slog.w(TAG, "Unable to prune stale trace file: " + files[i]);
+        try {
+            Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
+            for (int i = 0; i < files.length; ++i) {
+                if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) {
+                    if (!files[i].delete()) {
+                        Slog.w(TAG, "Unable to prune stale trace file: " + files[i]);
+                    }
                 }
             }
+        } catch (IllegalArgumentException e) {
+            // The modification times changed while we were sorting. Bail...
+            // https://issuetracker.google.com/169836837
+            Slog.w(TAG, "tombstone modification times changed while sorting; not pruning", e);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 47eb3eb..a0a596d 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -18,10 +18,16 @@
 
 import static android.net.ConnectivityManager.NetworkCallback;
 import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_3072_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_4096_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_CURVE_25519;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
 import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
 import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
@@ -29,8 +35,13 @@
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192;
 import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC;
 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
 import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -84,12 +95,6 @@
 public class VpnIkev2Utils {
     private static final String TAG = VpnIkev2Utils.class.getSimpleName();
 
-    // TODO: Use IKE library exposed constants when @SystemApi is updated.
-    /** IANA-defined 3072 group for use in IKEv2 */
-    private static final int DH_GROUP_3072_BIT_MODP = 15;
-    /** IANA-defined 4096 group for use in IKEv2 */
-    private static final int DH_GROUP_4096_BIT_MODP = 16;
-
     static IkeSessionParams buildIkeSessionParams(
             @NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
         final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
@@ -154,12 +159,14 @@
         // TODO: Add ability to filter this when IKEv2 API is made Public API
         final List<IkeSaProposal> proposals = new ArrayList<>();
 
-        // Encryption Algorithms: Currently only AES_CBC is supported.
         final IkeSaProposal.Builder normalModeBuilder = new IkeSaProposal.Builder();
 
-        // Currently only AES_CBC is supported.
+        // Add normal mode encryption algorithms
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_256);
         normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_192);
         normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
+        normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_128);
         normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
 
         // Authentication/Integrity Algorithms
@@ -167,9 +174,11 @@
         normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
         normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
         normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96);
+        normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96);
 
         // Add AEAD options
         final IkeSaProposal.Builder aeadBuilder = new IkeSaProposal.Builder();
+        aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED);
         aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
         aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
         aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
@@ -183,9 +192,17 @@
         // Add dh, prf for both builders
         for (final IkeSaProposal.Builder builder : Arrays.asList(normalModeBuilder, aeadBuilder)) {
             builder.addDhGroup(DH_GROUP_4096_BIT_MODP);
+
+            // Curve25519 has the same security strength as MODP 3072 and cost less bytes
+            builder.addDhGroup(DH_GROUP_CURVE_25519);
+
             builder.addDhGroup(DH_GROUP_3072_BIT_MODP);
             builder.addDhGroup(DH_GROUP_2048_BIT_MODP);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_512);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_384);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_256);
             builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC);
+            builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC);
             builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
         }
 
@@ -198,15 +215,23 @@
     private static List<ChildSaProposal> getChildSaProposals(List<String> allowedAlgorithms) {
         final List<ChildSaProposal> proposals = new ArrayList<>();
 
+        final List<Integer> aesKeyLenOptions =
+                Arrays.asList(KEY_LEN_AES_256, KEY_LEN_AES_192, KEY_LEN_AES_128);
+
         // Add non-AEAD options
         if (Ikev2VpnProfile.hasNormalModeAlgorithms(allowedAlgorithms)) {
             final ChildSaProposal.Builder normalModeBuilder = new ChildSaProposal.Builder();
 
             // Encryption Algorithms:
-            // AES-CBC is currently the only supported encryption algorithm.
-            normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
-            normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
-            normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
+            // AES-CBC and AES_CTR are currently the only supported encryption algorithms.
+            for (int len : aesKeyLenOptions) {
+                if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CTR)) {
+                    normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, len);
+                }
+                if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CBC)) {
+                    normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, len);
+                }
+            }
 
             // Authentication/Integrity Algorithms:
             // Guaranteed by Ikev2VpnProfile constructor to contain at least one of these.
@@ -219,6 +244,12 @@
             if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_HMAC_SHA256)) {
                 normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
             }
+            if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_XCBC)) {
+                normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96);
+            }
+            if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_CMAC)) {
+                normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96);
+            }
 
             ChildSaProposal proposal = normalModeBuilder.build();
             if (proposal.getIntegrityAlgorithms().isEmpty()) {
@@ -233,16 +264,27 @@
         if (Ikev2VpnProfile.hasAeadAlgorithms(allowedAlgorithms)) {
             final ChildSaProposal.Builder aeadBuilder = new ChildSaProposal.Builder();
 
-            // AES-GCM is currently the only supported AEAD algorithm
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
-            aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+            if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305)) {
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED);
+            }
+            if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_AES_GCM)) {
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
+                aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
+                aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
+                aeadBuilder.addEncryptionAlgorithm(
+                        ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
+                aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+            }
 
             proposals.add(aeadBuilder.build());
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0d06426..a1560b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9903,10 +9903,10 @@
     @Override
     public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
             String loaderIsa) {
-        if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
-                && Binder.getCallingUid() != Process.SYSTEM_UID) {
+        int callingUid = Binder.getCallingUid();
+        if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) {
             Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
-                    + Binder.getCallingUid());
+                    + callingUid);
             // Do not record dex loads from processes pretending to be system server.
             // Only the system server should be assigned the package "android", so reject calls
             // that don't satisfy the constraint.
@@ -9917,6 +9917,7 @@
             // in order to verify the expectations.
             return;
         }
+
         int userId = UserHandle.getCallingUserId();
         ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
         if (ai == null) {
@@ -9924,7 +9925,8 @@
                 + loadingPackageName + ", user=" + userId);
             return;
         }
-        mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
+        mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId,
+                Process.isIsolated(callingUid));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 37f3175..32ba26c 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -86,6 +86,11 @@
     // However it can load verification data - thus we pick the "verify" compiler filter.
     private static final String SYSTEM_SERVER_COMPILER_FILTER = "verify";
 
+    // The suffix we add to the package name when the loading happens in an isolated process.
+    // Note that the double dot creates and "invalid" package name which makes it clear that this
+    // is an artificially constructed name.
+    private static final String ISOLATED_PROCESS_PACKAGE_SUFFIX = "..isolated";
+
     private final Context mContext;
 
     // Maps package name to code locations.
@@ -166,12 +171,14 @@
      *     the class loader context that was used to load them.
      * @param loaderIsa the ISA of the app loading the dex files
      * @param loaderUserId the user id which runs the code loading the dex files
+     * @param loaderIsIsolatedProcess whether or not the loading process is isolated.
      */
     public void notifyDexLoad(ApplicationInfo loadingAppInfo,
-            Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) {
+            Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId,
+            boolean loaderIsIsolatedProcess) {
         try {
             notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
-                    loaderUserId);
+                    loaderUserId, loaderIsIsolatedProcess);
         } catch (Exception e) {
             Slog.w(TAG, "Exception while notifying dex load for package " +
                     loadingAppInfo.packageName, e);
@@ -181,7 +188,7 @@
     @VisibleForTesting
     /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
             Map<String, String> classLoaderContextMap, String loaderIsa,
-            int loaderUserId) {
+            int loaderUserId, boolean loaderIsIsolatedProcess) {
         if (classLoaderContextMap == null) {
             return;
         }
@@ -195,22 +202,36 @@
             return;
         }
 
+        // If this load is coming from an isolated process we need to be able to prevent profile
+        // based optimizations. This is because isolated processes are sandboxed and can only read
+        // world readable files, so they need world readable optimization files. An
+        // example of such a package is webview.
+        //
+        // In order to prevent profile optimization we pretend that the load is coming from a
+        // different package, and so we assign a artificial name to the loading package making it
+        // clear that it comes from an isolated process. This blends well with the entire
+        // usedByOthers logic without needing to special handle isolated process in all dexopt
+        // layers.
+        String loadingPackageAmendedName = loadingAppInfo.packageName;
+        if (loaderIsIsolatedProcess) {
+            loadingPackageAmendedName += ISOLATED_PROCESS_PACKAGE_SUFFIX;
+        }
         for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
             String dexPath = mapping.getKey();
             // Find the owning package name.
             DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
 
             if (DEBUG) {
-                Slog.i(TAG, loadingAppInfo.packageName
-                    + " loads from " + searchResult + " : " + loaderUserId + " : " + dexPath);
+                Slog.i(TAG, loadingPackageAmendedName
+                        + " loads from " + searchResult + " : " + loaderUserId + " : " + dexPath);
             }
 
             if (searchResult.mOutcome != DEX_SEARCH_NOT_FOUND) {
                 // TODO(calin): extend isUsedByOtherApps check to detect the cases where
                 // different apps share the same runtime. In that case we should not mark the dex
                 // file as isUsedByOtherApps. Currently this is a safe approximation.
-                boolean isUsedByOtherApps = !loadingAppInfo.packageName.equals(
-                        searchResult.mOwningPackageName);
+                boolean isUsedByOtherApps =
+                        !loadingPackageAmendedName.equals(searchResult.mOwningPackageName);
                 boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
                         searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
 
@@ -249,7 +270,7 @@
                     // async write to disk to make sure we don't loose the data in case of a reboot.
                     if (mPackageDexUsage.record(searchResult.mOwningPackageName,
                             dexPath, loaderUserId, loaderIsa, primaryOrSplit,
-                            loadingAppInfo.packageName, classLoaderContext, overwriteCLC)) {
+                            loadingPackageAmendedName, classLoaderContext, overwriteCLC)) {
                         mPackageDexUsage.maybeWriteAsync();
                     }
                 }
@@ -749,7 +770,7 @@
                     dexPath, userId, isa, /*primaryOrSplit*/ false,
                     loadingPackage,
                     PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT,
-                    /*overwriteCLC*/ false);
+                    /*overwriteCLC=*/ false);
             update |= newUpdate;
         }
         if (update) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 2e0cadf..8abe46f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -410,6 +410,17 @@
     }
 
     @Test
+    public void testNotifyUsedByIsolatedProcess() {
+        // Bar loads its own apk but as isolatedProcess.
+        notifyDexLoad(mBarUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0,
+                /*isolatedProcess=*/ true);
+
+        // Bar is used by an isolated process and should be marked as usedByOtherApps
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertIsUsedByOtherApps(mBarUser0, pui, true);
+    }
+
+    @Test
     public void testNotifyPackageUpdatedCodeLocations() {
         // Simulate a split update.
         String newSplit = mBarUser0.replaceLastSplit();
@@ -545,7 +556,7 @@
         List<String> classLoaders =
                 Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
         List<String> classPaths = Arrays.asList(classPath, classPath);
-        notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0);
+        notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0, /*isolatedProcess=*/ false);
 
         assertNoUseInfo(mBarUser0);
 
@@ -664,7 +675,8 @@
             expectedContexts[i] += contextSuffix;
         }
 
-        notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0);
+        notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0,
+                /*isolatedProcess=*/ false);
 
         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
         assertIsUsedByOtherApps(mFooUser0, pui, false);
@@ -838,26 +850,32 @@
             assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath));
         }
     }
+
     private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
+        notifyDexLoad(testData, dexPaths, loaderUserId, /*isolatedProcess=*/ false);
+    }
+
+    private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId,
+            boolean isolatedProcess) {
         // By default, assume a single class loader in the chain.
         // This makes writing tests much easier.
         List<String> classLoaders = Arrays.asList(testData.mClassLoader);
         List<String> classPaths = dexPaths != null
                 ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
-        notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
+        notifyDexLoad(testData, classLoaders, classPaths, loaderUserId, isolatedProcess);
     }
 
     private void notifyDexLoad(TestData testData, List<String> classLoaders,
-            List<String> classPaths, int loaderUserId) {
+            List<String> classPaths, int loaderUserId, boolean isolatedProcess) {
         String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
         // We call the internal function so any exceptions thrown cause test failures.
         List<String> dexPaths = classPaths != null
                 ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
-        notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId);
+        notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId, isolatedProcess);
     }
 
     private void notifyDexLoad(TestData testData, List<String> dexPaths,
-            String[] classLoaderContexts, int loaderUserId) {
+            String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess) {
         assertTrue(dexPaths.size() == classLoaderContexts.length);
         HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
         for (int i = 0; i < dexPaths.size(); i++) {
@@ -865,7 +883,7 @@
                     ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
         }
         mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
-                testData.mLoaderIsa, loaderUserId);
+                testData.mLoaderIsa, loaderUserId, isolatedProcess);
     }
 
     private String[] computeClassLoaderContexts(List<String> classLoaders,