Merge "nfc(api): Remove fg checks from API class"
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 6475144..a20191c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -1108,6 +1108,11 @@
         /**
          * Sets the enabled state of the automatic NAT-T keepalive timers
          *
+         * Note that if this builder was constructed with a {@link IkeTunnelConnectionParams},
+         * but this is called with {@code true}, the framework will automatically choose the
+         * appropriate keepalive timer and ignore the settings in the session params embedded
+         * in the connection params.
+         *
          * @param isEnabled {@code true} to enable automatic keepalive timers, based on internal
          *     platform signals. Defaults to {@code false}.
          * @return this {@link Builder} object to facilitate chaining of method calls
diff --git a/core/jni/android_media_MicrophoneInfo.cpp b/core/jni/android_media_MicrophoneInfo.cpp
index 65e30d8..18f8125 100644
--- a/core/jni/android_media_MicrophoneInfo.cpp
+++ b/core/jni/android_media_MicrophoneInfo.cpp
@@ -92,6 +92,7 @@
         env->DeleteLocalRef(jFrequencyResponse);
     }
     // Create a list of Pair for channel mapping.
+    jChannelMappings = env->NewObject(gArrayListClass, gArrayListCstor);
     const auto &channelMapping = micInfo.channel_mapping;
     for (size_t i = 0; i < std::size(channelMapping); i++) {
         int channelMappingType = channelMapping[i];
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 27db41c..171349a 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -841,7 +841,7 @@
         if (ringtoneUri != null) {
             final Uri cacheUri = getCacheForType(type, context.getUserId());
             try (InputStream in = openRingtone(context, ringtoneUri);
-                    OutputStream out = resolver.openOutputStream(cacheUri)) {
+                    OutputStream out = resolver.openOutputStream(cacheUri, "wt")) {
                 FileUtils.copy(in, out);
             } catch (IOException e) {
                 Log.w(TAG, "Failed to cache ringtone: " + e);
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 5237b4f..172aff7 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -14,7 +14,7 @@
   ~ limitations under the License
   -->
 
-<resources>
+<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <style name="TextAppearanceSmall">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
     </style>
@@ -73,7 +73,7 @@
     </style>
 
     <style name="TextAppearanceBroadcastDialogButton" parent="@android:TextAppearance.DeviceDefault.Headline">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
         <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item>
     </style>
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c15e419..ab2c002 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -25,6 +25,8 @@
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO;
+import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO;
 import static android.os.PowerWhitelistManager.REASON_VPN;
 import static android.os.UserHandle.PER_USER_RANGE;
 
@@ -251,6 +253,14 @@
      */
     private static final int STARTING_TOKEN = -1;
 
+    // TODO : read this from carrier config instead of a constant
+    @VisibleForTesting
+    public static final int AUTOMATIC_KEEPALIVE_DELAY_SECONDS = 30;
+
+    // Default keepalive timeout for carrier config is 5 minutes. Mimic this.
+    @VisibleForTesting
+    static final int DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT = 5 * 60;
+
     // TODO: create separate trackers for each unique VPN to support
     // automated reconnection
 
@@ -3071,6 +3081,7 @@
                             prepareStatusIntent();
                         }
                         agentConnect(this::onValidationStatus);
+                        mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
                         return; // Link properties are already sent.
                     } else {
                         // Underlying networks also set in agentConnect()
@@ -3179,6 +3190,7 @@
                     if (!removedAddrs.isEmpty()) {
                         startNewNetworkAgent(
                                 mNetworkAgent, "MTU too low for IPv6; restarting network agent");
+                        mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
 
                         for (LinkAddress removed : removedAddrs) {
                             mTunnelIface.removeAddress(
@@ -3251,14 +3263,22 @@
         private IkeSessionParams getIkeSessionParams(@NonNull Network underlyingNetwork) {
             final IkeTunnelConnectionParams ikeTunConnParams =
                     mProfile.getIkeTunnelConnectionParams();
+            final IkeSessionParams.Builder builder;
             if (ikeTunConnParams != null) {
-                final IkeSessionParams.Builder builder =
-                        new IkeSessionParams.Builder(ikeTunConnParams.getIkeSessionParams())
-                                .setNetwork(underlyingNetwork);
-                return builder.build();
+                builder = new IkeSessionParams.Builder(ikeTunConnParams.getIkeSessionParams())
+                        .setNetwork(underlyingNetwork);
             } else {
-                return VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, underlyingNetwork);
+                builder = VpnIkev2Utils.makeIkeSessionParamsBuilder(mContext, mProfile,
+                        underlyingNetwork);
             }
+            if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
+                builder.setNattKeepAliveDelaySeconds(guessNattKeepaliveTimerForNetwork());
+            }
+            if (mProfile.isAutomaticIpVersionSelectionEnabled()) {
+                builder.setIpVersion(guessEspIpVersionForNetwork());
+                builder.setEncapType(guessEspEncapTypeForNetwork());
+            }
+            return builder.build();
         }
 
         @NonNull
@@ -3322,6 +3342,23 @@
             startIkeSession(underlyingNetwork);
         }
 
+        private int guessEspIpVersionForNetwork() {
+            // TODO : guess the IP version based on carrier if auto IP version selection is enabled
+            return ESP_IP_VERSION_AUTO;
+        }
+
+        private int guessEspEncapTypeForNetwork() {
+            // TODO : guess the ESP encap type based on carrier if auto IP version selection is
+            // enabled
+            return ESP_ENCAP_TYPE_AUTO;
+        }
+
+        private int guessNattKeepaliveTimerForNetwork() {
+            // TODO : guess the keepalive delay based on carrier if auto keepalive timer is
+            // enabled
+            return AUTOMATIC_KEEPALIVE_DELAY_SECONDS;
+        }
+
         boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) {
             if (mSession == null || !mMobikeEnabled) return false;
 
@@ -3331,7 +3368,20 @@
                     + mCurrentToken
                     + " to network "
                     + underlyingNetwork);
-            mSession.setNetwork(underlyingNetwork);
+            final int ipVersion = mProfile.isAutomaticIpVersionSelectionEnabled()
+                    ? guessEspIpVersionForNetwork() : ESP_IP_VERSION_AUTO;
+            final int encapType = mProfile.isAutomaticIpVersionSelectionEnabled()
+                    ? guessEspEncapTypeForNetwork() : ESP_ENCAP_TYPE_AUTO;
+            final int keepaliveDelaySeconds;
+            if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
+                keepaliveDelaySeconds = guessNattKeepaliveTimerForNetwork();
+            } else if (mProfile.getIkeTunnelConnectionParams() != null) {
+                keepaliveDelaySeconds = mProfile.getIkeTunnelConnectionParams()
+                        .getIkeSessionParams().getNattKeepAliveDelaySeconds();
+            } else {
+                keepaliveDelaySeconds = DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
+            }
+            mSession.setNetwork(underlyingNetwork, ipVersion, encapType, keepaliveDelaySeconds);
             return true;
         }
 
@@ -4661,8 +4711,14 @@
         }
 
         /** Update the underlying network of the IKE Session */
-        public void setNetwork(@NonNull Network network) {
-            mImpl.setNetwork(network);
+        public void setNetwork(@NonNull Network network, int ipVersion, int encapType,
+                int keepaliveDelaySeconds) {
+            mImpl.setNetwork(network, ipVersion, encapType, keepaliveDelaySeconds);
+        }
+
+        /** Set the underpinned network */
+        public void setUnderpinnedNetwork(@NonNull Network underpinnedNetwork) {
+            mImpl.setUnderpinnedNetwork(underpinnedNetwork);
         }
 
         /** Forcibly terminate the IKE Session */
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 857c86d..a48c9fc 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -99,7 +99,7 @@
 public class VpnIkev2Utils {
     private static final String TAG = VpnIkev2Utils.class.getSimpleName();
 
-    static IkeSessionParams buildIkeSessionParams(
+    static IkeSessionParams.Builder makeIkeSessionParamsBuilder(
             @NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
         final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
         final IkeIdentification remoteId = parseIkeIdentification(profile.getServerAddr());
@@ -117,7 +117,7 @@
             ikeOptionsBuilder.addSaProposal(ikeProposal);
         }
 
-        return ikeOptionsBuilder.build();
+        return ikeOptionsBuilder;
     }
 
     static ChildSessionParams buildChildSessionParams(List<String> allowedAlgorithms) {
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index 90ddb6f..d2a6bf2 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -31,6 +31,7 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -299,6 +300,8 @@
 
     // Test that background dexopt under low storage conditions downgrades unused packages.
     @Test
+    @Ignore("b/251438180: This test has been failing for a long time; temporarily disable it while"
+            + " we investigate this issue.")
     public void testBackgroundDexOptDowngradeSuccessful() throws IOException {
         // Should be more than DOWNGRADE_AFTER_DAYS.
         long deltaDays = DOWNGRADE_AFTER_DAYS + 1;