Merge "cts case com.android.server.cts.GraphicsStatsValidationTest#testDaveyDrawFrame in modue CtsIncidentHostTestCases failed"
diff --git a/api/current.txt b/api/current.txt
index 07dc4d2..5974877 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -68706,7 +68706,7 @@
     method public java.util.regex.Matcher reset();
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
-    method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(int);
     method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 184ed44..863bfdf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4969,6 +4969,28 @@
     field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
     field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
     field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
+    field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
+    field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
+    field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
+    field public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617; // 0x651
+    field public static final int CODE_REJECT_INTERNAL_ERROR = 1612; // 0x64c
+    field public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608; // 0x648
+    field public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607; // 0x647
+    field public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611; // 0x64b
+    field public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616; // 0x650
+    field public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601; // 0x641
+    field public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618; // 0x652
+    field public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; // 0x655
+    field public static final int CODE_REJECT_ONGOING_E911_CALL = 1606; // 0x646
+    field public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620; // 0x654
+    field public static final int CODE_REJECT_ONGOING_HANDOVER = 1614; // 0x64e
+    field public static final int CODE_REJECT_QOS_FAILURE = 1613; // 0x64d
+    field public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604; // 0x644
+    field public static final int CODE_REJECT_UNKNOWN = 1600; // 0x640
+    field public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610; // 0x64a
+    field public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609; // 0x649
+    field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
+    field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
     field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
     field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
     field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
@@ -5240,6 +5262,7 @@
     method public android.telephony.ims.stub.ImsUtImplBase getUt();
     method public final void notifyCapabilitiesStatusChanged(android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
     method public final void notifyIncomingCall(android.telephony.ims.stub.ImsCallSessionImplBase, android.os.Bundle);
+    method public final void notifyRejectedCall(android.telephony.ims.ImsCallProfile, android.telephony.ims.ImsReasonInfo);
     method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
diff --git a/api/test-current.txt b/api/test-current.txt
index 709b37e..24d1275 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -426,6 +426,14 @@
 
 }
 
+package android.telecom {
+
+  public final class CallAudioState implements android.os.Parcelable {
+    ctor public CallAudioState(boolean, int, int, android.bluetooth.BluetoothDevice, java.util.Collection<android.bluetooth.BluetoothDevice>);
+  }
+
+}
+
 package android.telephony {
 
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6d55d0b..d56c726 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -368,12 +368,14 @@
                [Network Capabilities] Optional. A comma seprated list of network capabilities.
                    Values must be from NetworkCapabilities#NET_CAPABILITIES_* constants.
                [IP config] Optional. If empty or not specified - DHCP will be used, otherwise
-                    static IP address with the mask.
+                   use the following format to specify static IP configuration:
+		       ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+                       domains=<comma-sep-domains> 
          -->
     <string-array translatable="false" name="config_ethernet_interfaces">
         <!--
-        <item>eth1;12,13,14,15;192.168.0.10/24</item>
-        <item>eth2;;192.168.0.11/24</item>
+        <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
+        <item>eth2;;ip=192.168.0.11/24</item>
         -->
     </string-array>
 
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 8947bf0..fb78b3b 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -61,7 +61,7 @@
     <shortcode country="bh" pattern="\\d{1,5}" free="81181" />
 
     <!-- Brazil: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963" />
+    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" />
 
     <!-- Belarus: 4 digits -->
     <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
@@ -73,7 +73,7 @@
     <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765" />
 
     <!-- Chile: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="cl" pattern="\\d{4,5}" free="9963" />
+    <shortcode country="cl" pattern="\\d{4,5}" free="9963|9240" />
 
     <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
          http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
@@ -104,7 +104,7 @@
     <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}|22791|222145|22189" />
 
     <!-- Finland: 5-6 digits, premium 0600, 0700: http://en.wikipedia.org/wiki/Telephone_numbers_in_Finland -->
-    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789" />
+    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789|17110" />
 
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
          http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
@@ -136,7 +136,7 @@
     <shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />
 
     <!-- Indonesia: 1-5 digits (standard system default, not country specific) -->
-    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645" />
+    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363" />
 
     <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
          http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
@@ -190,7 +190,7 @@
     <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
 
     <!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" />
+    <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
 
     <!-- New Zealand: 3-4 digits, known premium codes listed -->
     <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
@@ -240,7 +240,7 @@
     <shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
 
     <!-- Thailand: 4186001 used by AIS_TH_DCB -->
-    <shortcode country="th" pattern="\\d{1,5}" free="4186001" />
+    <shortcode country="th" pattern="\\d{1,5}" premium="4\\d{6}" free="4186001" />
 
     <!-- Tajikistan: 4 digits, known premium codes listed -->
     <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 434dfdf..64085ea 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -167,8 +167,6 @@
             file="/system/framework/android.test.mock.jar" />
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar" />
-    <library name="javax.obex"
-            file="/system/framework/javax.obex.jar" />
 
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
diff --git a/media/lib/tvremote/Android.bp b/media/lib/tvremote/Android.bp
new file mode 100644
index 0000000..5f101a3
--- /dev/null
+++ b/media/lib/tvremote/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2018 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.
+//
+
+java_sdk_library {
+    name: "com.android.media.tv.remoteprovider",
+    srcs: ["java/**/*.java"],
+    api_packages: ["com.android.media.tv.remoteprovider"],
+    dex_preopt: {
+        enabled: false,
+    }
+}
diff --git a/media/lib/tvremote/Android.mk b/media/lib/tvremote/Android.mk
deleted file mode 100644
index 1ffdd62..0000000
--- a/media/lib/tvremote/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-LOCAL_PATH := $(call my-dir)
-
-# the tvremoteprovider library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= com.android.media.tv.remoteprovider
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-# ====  com.android.media.tvremote.xml lib def  ========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := com.android.media.tv.remoteprovider.xml
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_CLASS := ETC
-
-# This will install the file in /system/etc/permissions
-#
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
-
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
diff --git a/media/lib/tvremote/api/current.txt b/media/lib/tvremote/api/current.txt
new file mode 100644
index 0000000..eea9e9c
--- /dev/null
+++ b/media/lib/tvremote/api/current.txt
@@ -0,0 +1,21 @@
+package com.android.media.tv.remoteprovider {
+
+  public abstract class TvRemoteProvider {
+    ctor public TvRemoteProvider(android.content.Context);
+    method public void clearInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
+    method public void closeInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
+    method public android.os.IBinder getBinder();
+    method public final android.content.Context getContext();
+    method public void onInputBridgeConnected(android.os.IBinder);
+    method public void openRemoteInputBridge(android.os.IBinder, java.lang.String, int, int, int) throws java.lang.RuntimeException;
+    method public void sendKeyDown(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendKeyUp(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendPointerDown(android.os.IBinder, int, int, int) throws java.lang.RuntimeException;
+    method public void sendPointerSync(android.os.IBinder) throws java.lang.RuntimeException;
+    method public void sendPointerUp(android.os.IBinder, int) throws java.lang.RuntimeException;
+    method public void sendTimestamp(android.os.IBinder, long) throws java.lang.RuntimeException;
+    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider";
+  }
+
+}
+
diff --git a/media/lib/tvremote/api/removed.txt b/media/lib/tvremote/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/removed.txt
diff --git a/media/lib/tvremote/api/system-current.txt b/media/lib/tvremote/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/system-current.txt
diff --git a/media/lib/tvremote/api/system-removed.txt b/media/lib/tvremote/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/system-removed.txt
diff --git a/media/lib/tvremote/api/test-current.txt b/media/lib/tvremote/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/test-current.txt
diff --git a/media/lib/tvremote/api/test-removed.txt b/media/lib/tvremote/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/lib/tvremote/api/test-removed.txt
diff --git a/media/lib/tvremote/com.android.media.tv.remoteprovider.xml b/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
deleted file mode 100644
index dcf479a..0000000
--- a/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<permissions>
-    <library name="com.android.media.tv.remoteprovider"
-        file="/system/framework/com.android.media.tv.remoteprovider.jar" />
-</permissions>
\ No newline at end of file
diff --git a/obex/Android.bp b/obex/Android.bp
new file mode 100644
index 0000000..6558eb3
--- /dev/null
+++ b/obex/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2018 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.
+//
+
+java_sdk_library {
+    name: "javax.obex",
+    srcs: ["javax/**/*.java"],
+    api_packages: ["javax.obex"],
+}
diff --git a/obex/Android.mk b/obex/Android.mk
deleted file mode 100644
index e7c1fd3..0000000
--- a/obex/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obex
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obexstatic
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/obex/CleanSpec.mk b/obex/CleanSpec.mk
new file mode 100644
index 0000000..c104234
--- /dev/null
+++ b/obex/CleanSpec.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2018 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.
+#
+
+# runtime lib is renamed from javax.obex.jar to javax.obex.impl.jar
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/javax.obex.jar)
diff --git a/obex/api/current.txt b/obex/api/current.txt
new file mode 100644
index 0000000..1cd562f
--- /dev/null
+++ b/obex/api/current.txt
@@ -0,0 +1,12 @@
+package javax.obex {
+
+  public class ObexPacket {
+    method public static javax.obex.ObexPacket read(java.io.InputStream) throws java.io.IOException;
+    method public static javax.obex.ObexPacket read(int, java.io.InputStream) throws java.io.IOException;
+    field public int mHeaderId;
+    field public int mLength;
+    field public byte[] mPayload;
+  }
+
+}
+
diff --git a/obex/api/removed.txt b/obex/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/removed.txt
diff --git a/obex/api/system-current.txt b/obex/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-current.txt
diff --git a/obex/api/system-removed.txt b/obex/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-removed.txt
diff --git a/obex/api/test-current.txt b/obex/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-current.txt
diff --git a/obex/api/test-removed.txt b/obex/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-removed.txt
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 6186a78..e645adc 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -66,10 +66,11 @@
 LOCAL_MULTILIB := both
 LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
@@ -111,10 +112,11 @@
 
 LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 5ed14a0..6371d77 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -185,7 +185,12 @@
 
     private boolean startIPv4() { return configureIPv4(true); }
 
-    private void stopIPv4() { configureIPv4(false); }
+    private void stopIPv4() {
+        configureIPv4(false);
+        // NOTE: All of configureIPv4() will be refactored out of existence
+        // into calls to InterfaceController, shared with startIPv4().
+        mInterfaceCtrl.clearIPv4Address();
+    }
 
     // TODO: Refactor this in terms of calls to InterfaceController.
     private boolean configureIPv4(boolean enabled) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index da40692..e5cf394 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -179,6 +179,8 @@
 
     private final PowerManager.WakeLock mWakeLock;
 
+    private final boolean mUseBpfTrafficStats;
+
     private IConnectivityManager mConnManager;
 
     @VisibleForTesting
@@ -328,6 +330,7 @@
         mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
         mSystemDir = checkNotNull(systemDir, "missing systemDir");
         mBaseDir = checkNotNull(baseDir, "missing baseDir");
+        mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
     }
 
     @VisibleForTesting
@@ -916,7 +919,7 @@
     }
 
     private boolean checkBpfStatsEnable() {
-        return new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
+        return mUseBpfTrafficStats;
     }
 
     /**
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 63ae09a..7f821ff 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -231,10 +231,10 @@
     // TODO: Find an lighter weight approach.
     private class LoggingCallbackWrapper extends Callback {
         private static final String PREFIX = "INVOKE ";
-        private Callback mCallback;
+        private final Callback mCallback;
 
         public LoggingCallbackWrapper(Callback callback) {
-            mCallback = callback;
+            mCallback = (callback != null) ? callback : new Callback();
         }
 
         private void log(String msg) {
@@ -605,6 +605,13 @@
     private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
 
+    // Internal commands to use instead of trying to call transitionTo() inside
+    // a given State's enter() method. Calling transitionTo() from enter/exit
+    // encounters a Log.wtf() that can cause trouble on eng builds.
+    private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
+    private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
+    private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
+
     private static final int MAX_LOG_RECORDS = 500;
     private static final int MAX_PACKET_RECORDS = 100;
 
@@ -1418,6 +1425,9 @@
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
+                // Completed a life-cycle; send a final empty LinkProperties
+                // (cleared in resetLinkProperties() above) and record an event.
+                mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
                 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
                 mStartTimeMillis = 0;
             }
@@ -1476,13 +1486,17 @@
         public void enter() {
             if (mDhcpClient == null) {
                 // There's no DHCPv4 for which to wait; proceed to stopped.
-                transitionTo(mStoppedState);
+                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
             }
         }
 
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_STOPPING_TO_STOPPED:
+                    transitionTo(mStoppedState);
+                    break;
+
                 case CMD_STOP:
                     break;
 
@@ -1516,7 +1530,7 @@
             }
 
             if (readyToProceed()) {
-                transitionTo(mRunningState);
+                deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
             } else {
                 // Clear all IPv4 and IPv6 before proceeding to RunningState.
                 // Clean up any leftover state from an abnormal exit from
@@ -1533,6 +1547,10 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_STARTED_TO_RUNNING:
+                    transitionTo(mRunningState);
+                    break;
+
                 case CMD_STOP:
                     transitionTo(mStoppingState);
                     break;
@@ -1561,7 +1579,7 @@
             return HANDLED;
         }
 
-        boolean readyToProceed() {
+        private boolean readyToProceed() {
             return (!mLinkProperties.hasIPv4Address() &&
                     !mLinkProperties.hasGlobalIPv6Address());
         }
@@ -1593,13 +1611,13 @@
 
             if (mConfiguration.mEnableIPv6 && !startIPv6()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
             if (mConfiguration.mEnableIPv4 && !startIPv4()) {
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
@@ -1607,7 +1625,7 @@
             if ((config != null) && !applyInitialConfig(config)) {
                 // TODO introduce a new IpManagerEvent constant to distinguish this error case.
                 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
 
@@ -1621,7 +1639,7 @@
             if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
                 doImmediateProvisioningFailure(
                         IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
-                transitionTo(mStoppingState);
+                enqueueJumpToStoppingState();
                 return;
             }
         }
@@ -1658,6 +1676,10 @@
             resetLinkProperties();
         }
 
+        private void enqueueJumpToStoppingState() {
+            deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
+        }
+
         private ConnectivityPacketTracker createPacketTracker() {
             try {
                 return new ConnectivityPacketTracker(
@@ -1688,6 +1710,7 @@
         @Override
         public boolean processMessage(Message msg) {
             switch (msg.what) {
+                case CMD_JUMP_RUNNING_TO_STOPPING:
                 case CMD_STOP:
                     transitionTo(mStoppingState);
                     break;
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 4b827d2..e33ba7e 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.bluetooth.BluetoothDevice;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -100,6 +101,7 @@
     }
 
     /** @hide */
+    @TestApi
     public CallAudioState(boolean isMuted, @CallAudioRoute int route,
             @CallAudioRoute int supportedRouteMask,
             @Nullable BluetoothDevice activeBluetoothDevice,
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index d9fdd97..af4d8d7 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -207,23 +207,25 @@
     public static final int STATUS_UNKNOWN = 0;
 
     /**
-     * Indicates that the file is actively downloading.
+     * Indicates that the file is actively being downloaded.
      */
     public static final int STATUS_ACTIVELY_DOWNLOADING = 1;
 
     /**
-     * TODO: I don't know...
+     * Indicates that the file is awaiting the next download or repair operations. When a more
+     * precise status is known, the status will change to either {@link #STATUS_PENDING_REPAIR} or
+     * {@link #STATUS_PENDING_DOWNLOAD_WINDOW}.
      */
     public static final int STATUS_PENDING_DOWNLOAD = 2;
 
     /**
-     * Indicates that the file is being repaired after the download being interrupted.
+     * Indicates that the file is awaiting file repair after the download has ended.
      */
     public static final int STATUS_PENDING_REPAIR = 3;
 
     /**
      * Indicates that the file is waiting to download because its download window has not yet
-     * started.
+     * started and is scheduled for a future time.
      */
     public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4;
 
@@ -609,6 +611,9 @@
      * If the operation encountered an error, the error code will be delivered via
      * {@link MbmsDownloadSessionCallback#onError}.
      *
+     * Repeated calls to this method for the same {@link DownloadRequest} will replace the
+     * previously registered listener.
+     *
      * @param request The {@link DownloadRequest} that you want updates on.
      * @param executor The {@link Executor} on which calls to {@code listener } should be executed.
      * @param listener The listener that should be called when the middleware has information to
@@ -659,6 +664,9 @@
      * If the operation encountered an error, the error code will be delivered via
      * {@link MbmsDownloadSessionCallback#onError}.
      *
+     * Repeated calls to this method for the same {@link DownloadRequest} will replace the
+     * previously registered listener.
+     *
      * @param request The {@link DownloadRequest} provided during registration
      * @param listener The listener provided during registration.
      */
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 7d65430..e70e633 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -399,6 +399,160 @@
      */
     public static final int CODE_UNOBTAINABLE_NUMBER = 1515;
 
+    /**
+     * The rejection cause is not known.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNKNOWN = 1600;
+
+    /**
+     * Ongoing call, and call waiting is disabled.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601;
+
+    /**
+     * A call is ongoing on another sub.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602;
+
+    /**
+     * CDMA call collision.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_1X_COLLISION = 1603;
+
+    /**
+     * IMS is not registered for service yet.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604;
+
+    /**
+     * The call type is not allowed on the current RAT.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605;
+
+    /**
+     * And emergency call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_E911_CALL = 1606;
+
+    /**
+     * Another call is in the process of being establilshed.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607;
+
+    /**
+     * Maximum number of allowed calls are already in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608;
+
+    /**
+     * Invalid/unsupported SIP headers received.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609;
+
+    /**
+     * Invalid/unsupported SDP headers received.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610;
+
+    /**
+     * A call transfer is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611;
+
+    /**
+     * An internal error occured while processing the call.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_INTERNAL_ERROR = 1612;
+
+    /**
+     * Call failure due to lack of dedicated bearer.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_QOS_FAILURE = 1613;
+
+    /**
+     * A call handover is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_HANDOVER = 1614;
+
+    /**
+     * Video calling not supported with TTY.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615;
+
+    /**
+     * A call upgrade is in progress.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616;
+
+    /**
+     * Call from conference server, when TTY mode is ON.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617;
+
+    /**
+     * A conference call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618;
+
+    /**
+     * A video call with AVPF is not supported.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619;
+
+    /**
+     * And encrypted call is ongoing; other calls not supported.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620;
+
+    /**
+     * A CS call is ongoing.
+     * <p>
+     * Used with implicit call rejection.
+     */
+    public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
+
     /* OEM specific error codes. To be used by OEMs when they don't want to
    reveal error code which would be replaced by ERROR_UNSPECIFIED */
     public static final int CODE_OEM_CAUSE_1 = 0xf001;
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
index 904e7ca..7bbe30a 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelListener.aidl
@@ -18,6 +18,9 @@
 
 import android.os.Bundle;
 
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsReasonInfo;
+
 import com.android.ims.internal.IImsCallSession;
 
 /**
@@ -26,5 +29,6 @@
  */
 oneway interface IImsMmTelListener {
     void onIncomingCall(IImsCallSession c, in Bundle extras);
+    void onRejectedCall(in ImsCallProfile callProfile, in ImsReasonInfo reason);
     void onVoiceMessageCountUpdate(int count);
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index aaf1a1cf8..f12540f 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 
 import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsReasonInfo;
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsMultiEndpoint;
@@ -326,6 +327,16 @@
         }
 
         /**
+         * Called when the IMS provider implicitly rejects an incoming call during setup.
+         * @param callProfile An {@link ImsCallProfile} with the call details.
+         * @param reason The {@link ImsReasonInfo} reason for call rejection.
+         */
+        @Override
+        public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
+
+        }
+
+        /**
          * Updates the Listener when the voice message count for IMS has changed.
          * @param count an integer representing the new message count.
          */
@@ -429,6 +440,26 @@
     }
 
     /**
+     * Notify the framework that a call has been implicitly rejected by this MmTelFeature
+     * during call setup.
+     * @param callProfile The {@link ImsCallProfile} IMS call profile with details.
+     *        This can be null if no call information is available for the rejected call.
+     * @param reason The {@link ImsReasonInfo} call rejection reason.
+     */
+    public final void notifyRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
+        synchronized (mLock) {
+            if (mListener == null) {
+                throw new IllegalStateException("Session is not available.");
+            }
+            try {
+                mListener.onRejectedCall(callProfile, reason);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
      *
      * @hide
      */
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 61dbcc3..4c68c8b 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -9,9 +9,10 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index e682f79..b3a82f5 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -32,6 +32,8 @@
 # These are not normally accessible from apps so they must be explicitly included.
 LOCAL_JNI_SHARED_LIBRARIES := \
     android.hidl.token@1.0 \
+    $(UBSAN_RUNTIME_LIBRARY) \
+    libartbase \
     libbacktrace \
     libbase \
     libbinder \
@@ -57,7 +59,9 @@
     libvndksupport \
     libtinyxml2 \
     libunwindstack \
-    libutilscallstack
+    libutilscallstack \
+    libziparchive \
+    libz
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/tests/net/java/android/net/ip/IpClientTest.java b/tests/net/java/android/net/ip/IpClientTest.java
index e9e880d..89453e0 100644
--- a/tests/net/java/android/net/ip/IpClientTest.java
+++ b/tests/net/java/android/net/ip/IpClientTest.java
@@ -133,9 +133,18 @@
         verify(mNMService, times(1)).registerObserver(arg.capture());
         mObserver = arg.getValue();
         reset(mNMService);
+        // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
+        verify(mCb, never()).onLinkPropertiesChange(any());
+        reset(mCb);
         return ipc;
     }
 
+    private static LinkProperties makeEmptyLinkProperties(String iface) {
+        final LinkProperties empty = new LinkProperties();
+        empty.setInterfaceName(iface);
+        return empty;
+    }
+
     @Test
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
@@ -197,6 +206,8 @@
         ipc.shutdown();
         verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
         verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
+        verify(mCb, timeout(100).times(1))
+                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
     }
 
     @Test
@@ -246,6 +257,8 @@
         ipc.shutdown();
         verify(mNMService, timeout(100).times(1)).disableIpv6(iface);
         verify(mNMService, timeout(100).times(1)).clearInterfaceAddresses(iface);
+        verify(mCb, timeout(100).times(1))
+                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index d241b32..9994cdd 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -779,11 +779,12 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
 
-        // We verify get/set called twice here: once for setup and once during
+        // We verify get/set called thrice here: once for setup and twice during
         // teardown because all events happen over the course of the single
-        // dispatchAll() above.
+        // dispatchAll() above. Note that once the TISM IPv4 address config
+        // code is refactored the two calls during shutdown will revert to one.
         verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
-        verify(mNMService, times(2))
+        verify(mNMService, times(3))
                 .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
         verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index 7c77cf5..19d3a2e 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -173,6 +173,7 @@
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+        inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
         inOrder.verify(mTetherHelper).updateInterfaceState(
                 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         inOrder.verify(mTetherHelper).updateLinkProperties(
@@ -270,6 +271,7 @@
         inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
+        inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
         inOrder.verify(mTetherHelper).updateInterfaceState(
                 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         inOrder.verify(mTetherHelper).updateLinkProperties(
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 036bf5d8..3a312b0 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1923,6 +1923,12 @@
           .OptionalFlag("--version-name",
                         "Version name to inject into the AndroidManifest.xml if none is present.",
                         &options.manifest_fixer_options.version_name_default)
+          .OptionalSwitch("--replace-version",
+                         "If --version-code and/or --version-name are specified, these\n"
+                         "values will replace any value already in the manifest. By\n"
+                         "default, nothing is changed if the manifest already defines\n"
+                         "these attributes.",
+                         &options.manifest_fixer_options.replace_version)
           .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.",
                           &shared_lib)
           .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib)
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index e6271eb..ca7b653 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -237,6 +237,9 @@
   manifest_action.Action(FixCoreAppAttribute);
   manifest_action.Action([&](xml::Element* el) -> bool {
     if (options_.version_name_default) {
+      if (options_.replace_version) {
+        el->RemoveAttribute(xml::kSchemaAndroid, "versionName");
+      }
       if (el->FindAttribute(xml::kSchemaAndroid, "versionName") == nullptr) {
         el->attributes.push_back(
             xml::Attribute{xml::kSchemaAndroid, "versionName",
@@ -245,6 +248,9 @@
     }
 
     if (options_.version_code_default) {
+      if (options_.replace_version) {
+        el->RemoveAttribute(xml::kSchemaAndroid, "versionCode");
+      }
       if (el->FindAttribute(xml::kSchemaAndroid, "versionCode") == nullptr) {
         el->attributes.push_back(
             xml::Attribute{xml::kSchemaAndroid, "versionCode",
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index dbabab17..d7a5931 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -33,13 +33,22 @@
   Maybe<std::string> target_sdk_version_default;
   Maybe<std::string> rename_manifest_package;
   Maybe<std::string> rename_instrumentation_target_package;
+
+  // The version name to set if 'android:versionName' is not defined in <manifest> or if
+  // replace_version is set.
   Maybe<std::string> version_name_default;
+
+  // The version code to set if 'android:versionCode' is not defined in <manifest> or if
+  // replace_version is set.
   Maybe<std::string> version_code_default;
 
   // Wether validation errors should be treated only as warnings. If this is 'true', then an
   // incorrect node will not result in an error, but only as a warning, and the parsing will
   // continue.
   bool warn_validation = false;
+
+  // Whether to replace the manifest version with the the command line version
+  bool replace_version = false;
 };
 
 /**
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 84e367d..e6410c9 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -21,6 +21,7 @@
 using ::android::StringPiece;
 using ::testing::IsNull;
 using ::testing::NotNull;
+using ::testing::StrEq;
 
 namespace aapt {
 
@@ -339,6 +340,136 @@
   EXPECT_EQ(std::string("0x10000000"), attr->value);
 }
 
+TEST_F(ManifestFixerTest, DontUseDefaultVersionNameAndCode) {
+ManifestFixerOptions options;
+options.version_name_default = std::string("Beta");
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android"
+                android:versionCode="0x20000000"
+                android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_name_default = std::string("Beta");
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+              package="android"
+              android:versionCode="0x20000000"
+              android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Beta"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionName) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_name_default = std::string("Beta");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+            package="android"
+            android:versionCode="0x20000000"
+            android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Beta"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceVersionCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+options.version_code_default = std::string("0x10000000");
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+            package="android"
+            android:versionCode="0x20000000"
+            android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
+TEST_F(ManifestFixerTest, DontReplaceVersionNameOrCode) {
+ManifestFixerOptions options;
+options.replace_version = true;
+
+std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android"
+          android:versionCode="0x20000000"
+          android:versionName="Alpha" />)EOF",
+                                                          options);
+ASSERT_THAT(doc, NotNull());
+
+xml::Element* manifest_el = doc->root.get();
+ASSERT_THAT(manifest_el, NotNull());
+
+xml::Attribute* attr =
+    manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("Alpha"));
+
+attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ASSERT_THAT(attr, NotNull());
+EXPECT_THAT(attr->value, StrEq("0x20000000"));
+}
+
 TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
   EXPECT_EQ(nullptr,
             Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 1d122db..22767781 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -394,6 +394,15 @@
   return nullptr;
 }
 
+void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
+  auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
+    [&](const Attribute& attr) -> bool {
+      return ns == attr.namespace_uri && name == attr.name;
+    });
+
+  attributes.erase(new_attr_end, attributes.end());
+}
+
 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
   return FindChildWithAttribute(ns, name, {}, {}, {});
 }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 1542243..995cdb24 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -98,6 +98,9 @@
   Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
   const Attribute* FindAttribute(const android::StringPiece& ns,
                                  const android::StringPiece& name) const;
+  void RemoveAttribute(const android::StringPiece& ns,
+                       const android::StringPiece& name);
+
   Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
   Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
                                   const android::StringPiece& attr_ns,