Merge "Merge hidden API metadata into a single CSV file."
diff --git a/Android.mk b/Android.mk
index 82a661a..770ec20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -87,6 +87,7 @@
     frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
     frameworks/base/config/hiddenapi-light-greylist.txt \
     frameworks/base/config/hiddenapi-vendor-list.txt \
+    frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
     frameworks/base/config/hiddenapi-force-blacklist.txt \
     $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
     $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
@@ -98,6 +99,7 @@
 	    --input-greylists \
 	        frameworks/base/config/hiddenapi-light-greylist.txt \
 	        frameworks/base/config/hiddenapi-vendor-list.txt \
+	        frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
 	        <(comm -12 <(sort $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)) \
 	                   $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \
 	        $(PRIVATE_GREYLIST_INPUTS) \
diff --git a/api/current.txt b/api/current.txt
index aca5e51..1f29fcb0 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -42636,6 +42636,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
+    method public static int getSlotIndex(int);
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
@@ -42657,6 +42658,7 @@
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
     field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+    field public static final int INVALID_SIM_SLOT_INDEX = -1; // 0xffffffff
     field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 57f9efa..2d28126 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5140,6 +5140,11 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
+  public class PhoneStateListener {
+    method public void onRadioPowerStateChanged(int);
+    field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 4194304; // 0x400000
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
     method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
@@ -5267,6 +5272,7 @@
     method public boolean getEmergencyCallbackMode();
     method public java.lang.String getIsimDomain();
     method public int getPreferredNetworkType(int);
+    method public int getRadioPowerState();
     method public int getSimApplicationState();
     method public int getSimCardState();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5330,6 +5336,9 @@
     field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
     field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
     field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
+    field public static final int RADIO_POWER_OFF = 0; // 0x0
+    field public static final int RADIO_POWER_ON = 1; // 0x1
+    field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
     field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
     field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
     field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index dc39988..f0bc3d6 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -2860,16 +2860,6 @@
 Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
 Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale;
-Llibcore/io/Libcore;->os:Llibcore/io/Os;
-Llibcore/io/Memory;->peekByte(J)B
-Llibcore/io/Memory;->peekByteArray(J[BII)V
-Llibcore/io/Memory;->peekInt(JZ)I
-Llibcore/io/Memory;->peekLong(JZ)J
-Llibcore/io/Memory;->pokeByte(JB)V
-Llibcore/io/Memory;->pokeByteArray(J[BII)V
-Llibcore/io/Memory;->pokeInt(JIZ)V
-Llibcore/io/Memory;->pokeLong(JJZ)V
-Llibcore/io/Streams;->copy(Ljava/io/InputStream;Ljava/io/OutputStream;)I
 Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap;
 Llibcore/util/ZoneInfo;->mTransitions:[J
 Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
diff --git a/config/hiddenapi-max-sdk-p-blacklist.txt b/config/hiddenapi-max-sdk-p-blacklist.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/hiddenapi-max-sdk-p-blacklist.txt
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c496ff4..1fbfa40 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2731,7 +2731,10 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
+            android.Manifest.permission.NETWORK_STACK})
     @SystemApi
     public void setAirplaneMode(boolean enable) {
         try {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 20ca19b..c9c4205 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -388,10 +388,10 @@
 
     /**
      * Setup a new physical network.
-     * @param permission null if no permissions required to access this network.  PERMISSION_NETWORK
-     *                   or PERMISSION_SYSTEM to set respective permission.
+     * @param permission PERMISSION_NONE if no permissions required to access this network.
+     *                   PERMISSION_NETWORK or PERMISSION_SYSTEM to set respective permission.
      */
-    void createPhysicalNetwork(int netId, String permission);
+    void createPhysicalNetwork(int netId, int permission);
 
     /**
      * Setup a new VPN.
@@ -420,10 +420,10 @@
 
     /**
      * Set permission for a network.
-     * @param permission null to clear permissions. PERMISSION_NETWORK or PERMISSION_SYSTEM to set
-     *                   permission.
+     * @param permission PERMISSION_NONE to clear permissions.
+     *                   PERMISSION_NETWORK or PERMISSION_SYSTEM to set permission.
      */
-    void setNetworkPermission(int netId, String permission);
+    void setNetworkPermission(int netId, int permission);
 
     void setPermission(String permission, in int[] uids);
     void clearPermission(in int[] uids);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index cec0df0..959534d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -34,6 +34,8 @@
     public static final String FFLAG_PREFIX = "sys.fflag.";
     public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override.";
     public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
+    public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
+    public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
 
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
@@ -46,6 +48,7 @@
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "false");
+        DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
     }
 
     /**
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index c3ba9ba..9341d9a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -23,6 +23,7 @@
 #include <atomic>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <mutex>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -69,6 +70,7 @@
     // Class state.
     jclass mClass;
     jmethodID mExecTransact;
+    jmethodID mGetInterfaceDescriptor;
 
     // Object state.
     jfieldID mObject;
@@ -328,8 +330,32 @@
         env->DeleteGlobalRef(mObject);
     }
 
-    virtual status_t onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
+    const String16& getInterfaceDescriptor() const override
+    {
+        call_once(mPopulateDescriptor, [this] {
+            JNIEnv* env = javavm_to_jnienv(mVM);
+
+            ALOGV("getInterfaceDescriptor() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
+
+            jstring descriptor = (jstring)env->CallObjectMethod(mObject, gBinderOffsets.mGetInterfaceDescriptor);
+
+            if (descriptor == nullptr) {
+                return;
+            }
+
+            static_assert(sizeof(jchar) == sizeof(char16_t), "");
+            const jchar* descriptorChars = env->GetStringChars(descriptor, nullptr);
+            const char16_t* rawDescriptor = reinterpret_cast<const char16_t*>(descriptorChars);
+            jsize rawDescriptorLen = env->GetStringLength(descriptor);
+            mDescriptor = String16(rawDescriptor, rawDescriptorLen);
+            env->ReleaseStringChars(descriptor, descriptorChars);
+        });
+
+        return mDescriptor;
+    }
+
+    status_t onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
     {
         JNIEnv* env = javavm_to_jnienv(mVM);
 
@@ -378,7 +404,7 @@
         return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
     }
 
-    virtual status_t dump(int fd, const Vector<String16>& args)
+    status_t dump(int fd, const Vector<String16>& args) override
     {
         return 0;
     }
@@ -386,6 +412,9 @@
 private:
     JavaVM* const   mVM;
     jobject const   mObject;  // GlobalRef to Java Binder
+
+    mutable std::once_flag mPopulateDescriptor;
+    mutable String16 mDescriptor;
 };
 
 // ----------------------------------------------------------------------------
@@ -939,6 +968,8 @@
 
     gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
     gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
+    gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
+        "()Ljava/lang/String;");
     gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
 
     return RegisterMethodsOrDie(
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 307e2e8..041fb7e 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -47,7 +47,6 @@
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
-    conscrypt \
     telephony-common \
     org.apache.http.legacy \
     android.test.base \
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 5814df5..8fd02c0 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -472,8 +472,8 @@
          *     <tr>
          *         <td>Electro-optical transfer function (EOTF)</td>
          *         <td colspan="4">\(\begin{equation}
-         *             C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.039 \\
-         *             \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.039 \end{cases}
+         *             C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.04045 \\
+         *             \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases}
          *             \end{equation}\)
          *         </td>
          *     </tr>
@@ -1484,7 +1484,7 @@
                 "Display P3",
                 new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
                 ILLUMINANT_D65,
-                new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.039, 2.4),
+                new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
                 Named.DISPLAY_P3.ordinal()
         );
         sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 8f58f74..66a5477 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -39,7 +39,7 @@
 
 static const std::string kResourcesArsc("resources.arsc");
 
-ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path)
+ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path)
     : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
 }
 
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 69702e3..db2d038 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -27,6 +27,9 @@
 #include "androidfw/LoadedArsc.h"
 #include "androidfw/misc.h"
 
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
+
 namespace android {
 
 class LoadedIdmap;
@@ -88,9 +91,9 @@
   // Creates an Asset from any file on the file system.
   static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
 
-  ApkAssets(void* unmanaged_handle, const std::string& path);
+  ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path);
 
-  using ZipArchivePtr = std::unique_ptr<void, void(*)(void*)>;
+  using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>;
 
   ZipArchivePtr zip_handle_;
   const std::string path_;
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 03154d0..c221e3b 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -41,7 +41,8 @@
 #include <unistd.h>
 #include <time.h>
 
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
 
 namespace android {
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 8fa9597..d267ead 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -110,6 +110,10 @@
         mHiSyncId = id;
     }
 
+    public boolean isHearingAidDevice() {
+        return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
+    }
+
     /**
      * Last time a bt profile auto-connect was attempted.
      * If an ACTION_UUID intent comes in within
@@ -144,8 +148,8 @@
 
     void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
         if (Utils.D) {
-            Log.d(TAG, "onProfileStateChanged: profile " + profile +
-                    " newProfileState " + newProfileState);
+            Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device=" + mDevice
+                    + ", newProfileState " + newProfileState);
         }
         if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
         {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index b360faab..3a56627 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -162,14 +162,14 @@
      */
     public synchronized String getHearingAidPairDeviceSummary(CachedBluetoothDevice device) {
         String pairDeviceSummary = null;
-        if (device.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
-            for (CachedBluetoothDevice hearingAidDevice : mHearingAidDevicesNotAddedInCache) {
-                if (hearingAidDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
-                    && hearingAidDevice.getHiSyncId() == device.getHiSyncId()) {
-                    pairDeviceSummary = hearingAidDevice.getConnectionSummary();
-                }
-            }
+        CachedBluetoothDevice otherHearingAidDevice =
+            getHearingAidOtherDevice(device, device.getHiSyncId());
+        if (otherHearingAidDevice != null) {
+            pairDeviceSummary = otherHearingAidDevice.getConnectionSummary();
         }
+        log("getHearingAidPairDeviceSummary: pairDeviceSummary=" + pairDeviceSummary
+            + ", otherHearingAidDevice=" + otherHearingAidDevice);
+ 
         return pairDeviceSummary;
     }
 
@@ -358,7 +358,7 @@
         }
     }
 
-    private CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
+    public CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
                                                            long hiSyncId) {
         if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
             return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 75cbb65..88ec1d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -378,9 +378,10 @@
                 Log.i(TAG, "Failed to connect " + mProfile + " device");
             }
 
-            if (getHearingAidProfile() != null &&
-                mProfile instanceof HearingAidProfile &&
-                (newState == BluetoothProfile.STATE_CONNECTED)) {
+            boolean isHearingAidProfile = (getHearingAidProfile() != null) &&
+                (mProfile instanceof HearingAidProfile);
+
+            if (isHearingAidProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
                 // Check if the HiSyncID has being initialized
                 if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
 
@@ -393,10 +394,22 @@
                 }
             }
 
-            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
-                    mProfile.getProfileId());
             cachedDevice.onProfileStateChanged(mProfile, newState);
             cachedDevice.refresh();
+
+            if (isHearingAidProfile) {
+                CachedBluetoothDevice otherDevice =
+                    mDeviceManager.getHearingAidOtherDevice(cachedDevice, cachedDevice.getHiSyncId());
+                if (otherDevice != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Refreshing other hearing aid=" + otherDevice
+                               + ", newState=" + newState);
+                    }
+                    otherDevice.refresh();
+                }
+            }
+            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
+                    mProfile.getProfileId());
         }
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 6d6a132..a3d10a2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -828,4 +828,20 @@
         assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
         assertThat(cachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
     }
+
+    /**
+     * Test to verify getHearingAidOtherDevice() for hearing aid devices with same HiSyncId.
+     */
+    @Test
+    public void testGetHearingAidOtherDevice_bothHearingAidsPaired_returnsOtherDevice() {
+        mCachedDevice1.setHiSyncId(HISYNCID1);
+        mCachedDevice2.setHiSyncId(HISYNCID1);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+        mCachedDeviceManager.mHearingAidDevicesNotAddedInCache.add(mCachedDevice2);
+        doAnswer((invocation) -> DEVICE_SUMMARY_1).when(mCachedDevice1).getConnectionSummary();
+        doAnswer((invocation) -> DEVICE_SUMMARY_2).when(mCachedDevice2).getConnectionSummary();
+
+        assertThat(mCachedDeviceManager.getHearingAidOtherDevice(mCachedDevice1, HISYNCID1))
+            .isEqualTo(mCachedDevice2);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 927a94f..16a292b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -28,6 +28,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.media.AudioManager;
@@ -572,4 +573,16 @@
 
         assertThat(mCachedDevice.isHfpDevice()).isFalse();
     }
+
+    @Test
+    public void testIsHearingAidDevice_isHearingAidDevice() {
+        mCachedDevice.setHiSyncId(0x1234);
+        assertThat(mCachedDevice.isHearingAidDevice()).isTrue();
+    }
+
+    @Test
+    public void testIsHearingAidDevice_isNotHearingAidDevice() {
+        mCachedDevice.setHiSyncId(BluetoothHearingAid.HI_SYNC_ID_INVALID);
+        assertThat(mCachedDevice.isHearingAidDevice()).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index ca997bf8..17af429 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -51,6 +52,7 @@
 @RunWith(RobolectricTestRunner.class)
 @Config(resourceDir = "../../res")
 public class LocalBluetoothProfileManagerTest {
+    private final static long HI_SYNC_ID = 0x1234;
     @Mock
     private CachedBluetoothDeviceManager mDeviceManager;
     @Mock
@@ -61,6 +63,8 @@
     private BluetoothDevice mDevice;
     @Mock
     private CachedBluetoothDevice mCachedBluetoothDevice;
+    @Mock
+    private CachedBluetoothDevice mHearingAidOtherDevice;
 
     private Context mContext;
     private LocalBluetoothProfileManager mProfileManager;
@@ -199,6 +203,32 @@
     }
 
     /**
+     * Verify BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
+     * refresh both sides devices.
+     */
+    @Test
+    public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldRefreshBothSides() {
+        ArrayList<Integer> supportProfiles = new ArrayList<>();
+        supportProfiles.add(BluetoothProfile.HEARING_AID);
+        when(mAdapter.getSupportedProfiles()).thenReturn(supportProfiles);
+        when(mCachedBluetoothDevice.getHiSyncId()).thenReturn(HI_SYNC_ID);
+        when(mDeviceManager.getHearingAidOtherDevice(mCachedBluetoothDevice, HI_SYNC_ID))
+            .thenReturn(mHearingAidOtherDevice);
+
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        mIntent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mCachedBluetoothDevice).refresh();
+        verify(mHearingAidOtherDevice).refresh();
+    }
+
+    /**
      * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
      * profile connection state changed callback
      */
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a090f6d..abce8cf 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -55,6 +55,7 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
     <!-- Development tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.SET_DEBUG_APP" />
     <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436de..d033057 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
         android:paddingEnd="@dimen/status_bar_padding_end"
         android:orientation="horizontal"
         >
-        <ViewStub
-            android:id="@+id/operator_name"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout="@layout/operator_name" />
         <FrameLayout
             android:layout_height="match_parent"
             android:layout_width="0dp"
@@ -70,6 +65,12 @@
                 android:layout_width="match_parent"
                 android:clipChildren="false"
             >
+                <ViewStub
+                    android:id="@+id/operator_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:layout="@layout/operator_name" />
+
                 <com.android.systemui.statusbar.policy.Clock
                     android:id="@+id/clock"
                     android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 409a783..118f1e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -47,6 +47,7 @@
     private final NotificationStackScrollLayout mStackScroller;
     private final HeadsUpStatusBarView mHeadsUpStatusBarView;
     private final View mClockView;
+    private final View mOperatorNameView;
     private final DarkIconDispatcher mDarkIconDispatcher;
     private final NotificationPanelView mPanelView;
     private final Consumer<ExpandableNotificationRow>
@@ -61,8 +62,10 @@
     private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
             (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
                     -> updatePanelTranslation();
+    private boolean mAnimationsEnabled = true;
     Point mPoint;
 
+
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
             HeadsUpManagerPhone headsUpManager,
@@ -71,7 +74,8 @@
                 statusbarView.findViewById(R.id.heads_up_status_bar_view),
                 statusbarView.findViewById(R.id.notification_stack_scroller),
                 statusbarView.findViewById(R.id.notification_panel),
-                statusbarView.findViewById(R.id.clock));
+                statusbarView.findViewById(R.id.clock),
+                statusbarView.findViewById(R.id.operator_name_frame));
     }
 
     @VisibleForTesting
@@ -81,7 +85,8 @@
             HeadsUpStatusBarView headsUpStatusBarView,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView panelView,
-            View clockView) {
+            View clockView,
+            View operatorNameView) {
         mNotificationIconAreaController = notificationIconAreaController;
         mHeadsUpManager = headsUpManager;
         mHeadsUpManager.addListener(this);
@@ -97,6 +102,7 @@
         mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mStackScroller.setHeadsUpAppearanceController(this);
         mClockView = clockView;
+        mOperatorNameView = operatorNameView;
         mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
         mDarkIconDispatcher.addDarkReceiver(this);
     }
@@ -205,20 +211,52 @@
             mShown = isShown;
             if (isShown) {
                 mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
-                CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
-                        CONTENT_FADE_DELAY /* delay */);
-                CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
-                        0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+                show(mHeadsUpStatusBarView);
+                hide(mClockView, View.INVISIBLE);
+                if (mOperatorNameView != null) {
+                    hide(mOperatorNameView, View.INVISIBLE);
+                }
             } else {
-                CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
-                        CONTENT_FADE_DELAY /* delay */);
-                CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
-                        0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+                show(mClockView);
+                if (mOperatorNameView != null) {
+                    show(mOperatorNameView);
+                }
+                hide(mHeadsUpStatusBarView, View.GONE);
             }
         }
     }
 
+    /**
+     * Hides the view and sets the state to endState when finished.
+     *
+     * @param view The view to hide.
+     * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+     * @see View#setVisibility(int)
+     *
+     */
+    private void hide(View view, int endState) {
+        if (mAnimationsEnabled) {
+            CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+                    0 /* delay */, () -> view.setVisibility(endState));
+        } else {
+            view.setVisibility(endState);
+        }
+    }
+
+    private void show(View view) {
+        if (mAnimationsEnabled) {
+            CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+                    CONTENT_FADE_DELAY /* delay */);
+        } else {
+            view.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @VisibleForTesting
+    void setAnimationsEnabled(boolean enabled) {
+        mAnimationsEnabled = enabled;
+    }
+
     @VisibleForTesting
     public boolean isShown() {
         return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
index af99236..e85dee8 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
@@ -51,7 +51,9 @@
     public void onTuningChanged(String key, String newValue) {
         int dimen = mDefaultSize;
         if (newValue != null) {
-            dimen = (int) (Integer.parseInt(newValue) * mDensity);
+            try {
+                dimen = (int) (Integer.parseInt(newValue) * mDensity);
+            } catch (NumberFormatException ex) {}
         }
         int left = mView.isLayoutRtl() ? FLAG_END : FLAG_START;
         int right = mView.isLayoutRtl() ? FLAG_START : FLAG_END;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 537bfd4..3c5c0b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -61,6 +61,7 @@
     private ExpandableNotificationRow mFirst;
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
     private HeadsUpManagerPhone mHeadsUpManager;
+    private View mOperatorNameView;
 
     @Before
     public void setUp() throws Exception {
@@ -70,13 +71,15 @@
         mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
                 mock(TextView.class));
         mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mOperatorNameView = new View(mContext);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
-                new View(mContext));
+                new View(mContext),
+                mOperatorNameView);
         mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
     }
 
@@ -123,6 +126,22 @@
     }
 
     @Test
+    public void testOperatorNameViewUpdated() {
+        mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+        mFirst.setPinned(true);
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+        when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+        mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+        Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+        mFirst.setPinned(false);
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+        mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+        Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+    }
+
+    @Test
     public void testDestroy() {
         reset(mHeadsUpManager);
         reset(mDarkIconDispatcher);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 99e0056..49de4b1 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -53,12 +53,16 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
 import android.util.Slog;
 import android.util.StatsLog;
 
@@ -386,6 +390,15 @@
         mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
         mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
 
+        // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
+        boolean isHearingAidEnabled;
+        String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
+        if (!TextUtils.isEmpty(value)) {
+            isHearingAidEnabled = Boolean.parseBoolean(value);
+            Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
+            FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
+        }
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4b77c69..b750d79 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1679,6 +1679,16 @@
                 "ConnectivityService");
     }
 
+    private void enforceAnyPermissionOf(String... permissions) {
+        for (String permission : permissions) {
+            if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+                return;
+            }
+        }
+        throw new SecurityException(
+            "Requires one of the following permissions: " + String.join(", ", permissions) + ".");
+    }
+
     private void enforceInternetPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INTERNET,
@@ -1723,6 +1733,13 @@
                 "ConnectivityService");
     }
 
+    private void enforceNetworkStackSettingsOrSetup() {
+        enforceAnyPermissionOf(
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD,
+            android.Manifest.permission.NETWORK_STACK);
+    }
+
     private boolean checkNetworkStackPermission() {
         return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.NETWORK_STACK);
@@ -3478,7 +3495,7 @@
         ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
 
         if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
-            mProxyTracker.sendProxyBroadcast(mProxyTracker.getDefaultProxy());
+            mProxyTracker.sendProxyBroadcast();
         }
     }
 
@@ -3984,7 +4001,7 @@
 
     @Override
     public void setAirplaneMode(boolean enable) {
-        enforceConnectivityInternalPermission();
+        enforceNetworkStackSettingsOrSetup();
         final long ident = Binder.clearCallingIdentity();
         try {
             final ContentResolver cr = mContext.getContentResolver();
@@ -4765,15 +4782,14 @@
         }
     }
 
-    private String getNetworkPermission(NetworkCapabilities nc) {
-        // TODO: make these permission strings AIDL constants instead.
+    private int getNetworkPermission(NetworkCapabilities nc) {
         if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
-            return NetworkManagementService.PERMISSION_SYSTEM;
+            return INetd.PERMISSION_SYSTEM;
         }
         if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
-            return NetworkManagementService.PERMISSION_NETWORK;
+            return INetd.PERMISSION_NETWORK;
         }
-        return null;
+        return INetd.PERMISSION_NONE;
     }
 
     /**
@@ -4846,9 +4862,9 @@
 
         if (Objects.equals(nai.networkCapabilities, newNc)) return;
 
-        final String oldPermission = getNetworkPermission(nai.networkCapabilities);
-        final String newPermission = getNetworkPermission(newNc);
-        if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
+        final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+        final int newPermission = getNetworkPermission(newNc);
+        if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
             try {
                 mNMS.setNetworkPermission(nai.network.netId, newPermission);
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 94a15f7..ab50059 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -169,19 +169,6 @@
      */
     public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
 
-    /**
-     * String to pass to netd to indicate that a network is only accessible
-     * to apps that have the CHANGE_NETWORK_STATE permission.
-     */
-    public static final String PERMISSION_NETWORK = "NETWORK";
-
-    /**
-     * String to pass to netd to indicate that a network is only
-     * accessible to system apps and those with the CONNECTIVITY_INTERNAL
-     * permission.
-     */
-    public static final String PERMISSION_SYSTEM = "SYSTEM";
-
     static class NetdResponseCode {
         /* Keep in sync with system/netd/server/ResponseCode.h */
         public static final int InterfaceListResult       = 110;
@@ -222,6 +209,9 @@
 
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
 
+    static final boolean MODIFY_OPERATION_ADD = true;
+    static final boolean MODIFY_OPERATION_REMOVE = false;
+
     /**
      * Binder context for this service
      */
@@ -1117,41 +1107,47 @@
 
     @Override
     public void addRoute(int netId, RouteInfo route) {
-        modifyRoute("add", "" + netId, route);
+        modifyRoute(MODIFY_OPERATION_ADD, netId, route);
     }
 
     @Override
     public void removeRoute(int netId, RouteInfo route) {
-        modifyRoute("remove", "" + netId, route);
+        modifyRoute(MODIFY_OPERATION_REMOVE, netId, route);
     }
 
-    private void modifyRoute(String action, String netId, RouteInfo route) {
+    private void modifyRoute(boolean add, int netId, RouteInfo route) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final Command cmd = new Command("network", "route", action, netId);
-
-        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
-        cmd.appendArg(route.getInterface());
-        cmd.appendArg(route.getDestination().toString());
+        final String ifName = route.getInterface();
+        final String dst = route.getDestination().toString();
+        final String nextHop;
 
         switch (route.getType()) {
             case RouteInfo.RTN_UNICAST:
                 if (route.hasGateway()) {
-                    cmd.appendArg(route.getGateway().getHostAddress());
+                    nextHop = route.getGateway().getHostAddress();
+                } else {
+                    nextHop = INetd.NEXTHOP_NONE;
                 }
                 break;
             case RouteInfo.RTN_UNREACHABLE:
-                cmd.appendArg("unreachable");
+                nextHop = INetd.NEXTHOP_UNREACHABLE;
                 break;
             case RouteInfo.RTN_THROW:
-                cmd.appendArg("throw");
+                nextHop = INetd.NEXTHOP_THROW;
+                break;
+            default:
+                nextHop = INetd.NEXTHOP_NONE;
                 break;
         }
-
         try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            if (add) {
+                mNetdService.networkAddRoute(netId, ifName, dst, nextHop);
+            } else {
+                mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop);
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -1911,44 +1907,21 @@
     @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
-        argv[0] = "users";
-        argv[1] = "add";
-        argv[2] = netId;
-        int argc = 3;
-        // Avoid overly long commands by limiting number of UID ranges per command.
-        for (int i = 0; i < ranges.length; i++) {
-            argv[argc++] = ranges[i].toString();
-            if (i == (ranges.length - 1) || argc == argv.length) {
-                try {
-                    mConnector.execute("network", Arrays.copyOf(argv, argc));
-                } catch (NativeDaemonConnectorException e) {
-                    throw e.rethrowAsParcelableException();
-                }
-                argc = 3;
-            }
+
+        try {
+            mNetdService.networkAddUidRanges(netId, ranges);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
     @Override
     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
-        argv[0] = "users";
-        argv[1] = "remove";
-        argv[2] = netId;
-        int argc = 3;
-        // Avoid overly long commands by limiting number of UID ranges per command.
-        for (int i = 0; i < ranges.length; i++) {
-            argv[argc++] = ranges[i].toString();
-            if (i == (ranges.length - 1) || argc == argv.length) {
-                try {
-                    mConnector.execute("network", Arrays.copyOf(argv, argc));
-                } catch (NativeDaemonConnectorException e) {
-                    throw e.rethrowAsParcelableException();
-                }
-                argc = 3;
-            }
+        try {
+            mNetdService.networkRemoveUidRanges(netId, ranges);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2406,17 +2379,13 @@
     }
 
     @Override
-    public void createPhysicalNetwork(int netId, String permission) {
+    public void createPhysicalNetwork(int netId, int permission) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            if (permission != null) {
-                mConnector.execute("network", "create", netId, permission);
-            } else {
-                mConnector.execute("network", "create", netId);
-            }
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkCreatePhysical(netId, permission);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2425,10 +2394,9 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
-                    secure ? "1" : "0");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkCreateVpn(netId, hasDNS, secure);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2449,20 +2417,24 @@
 
     @Override
     public void addInterfaceToNetwork(String iface, int netId) {
-        modifyInterfaceInNetwork("add", "" + netId, iface);
+        modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
     }
 
     @Override
     public void removeInterfaceFromNetwork(String iface, int netId) {
-        modifyInterfaceInNetwork("remove", "" + netId, iface);
+        modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, netId, iface);
     }
 
-    private void modifyInterfaceInNetwork(String action, String netId, String iface) {
+    private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mConnector.execute("network", "interface", action, netId, iface);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            if (add) {
+                mNetdService.networkAddInterface(netId, iface);
+            } else {
+                mNetdService.networkRemoveInterface(netId, iface);
+            }
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2470,20 +2442,20 @@
     public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
-
-        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
         final LinkAddress la = routeInfo.getDestinationLinkAddress();
-        cmd.appendArg(routeInfo.getInterface());
-        cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
-        if (routeInfo.hasGateway()) {
-            cmd.appendArg(routeInfo.getGateway().getHostAddress());
-        }
+        final String ifName = routeInfo.getInterface();
+        final String dst = la.toString();
+        final String nextHop;
 
+        if (routeInfo.hasGateway()) {
+            nextHop = routeInfo.getGateway().getHostAddress();
+        } else {
+            nextHop = "";
+        }
         try {
-            mConnector.execute(cmd);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2492,9 +2464,9 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "default", "set", netId);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkSetDefault(netId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2503,49 +2475,41 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "default", "clear");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkClearDefault();
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
     @Override
-    public void setNetworkPermission(int netId, String permission) {
+    public void setNetworkPermission(int netId, int permission) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            if (permission != null) {
-                mConnector.execute("network", "permission", "network", "set", permission, netId);
-            } else {
-                mConnector.execute("network", "permission", "network", "clear", netId);
-            }
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkSetPermissionForNetwork(netId, permission);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
+    private int parsePermission(String permission) {
+        if (permission.equals("NETWORK")) {
+            return INetd.PERMISSION_NETWORK;
+        }
+        if (permission.equals("SYSTEM")) {
+            return INetd.PERMISSION_SYSTEM;
+        }
+        return INetd.PERMISSION_NONE;
+    }
 
     @Override
     public void setPermission(String permission, int[] uids) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
-        argv[0] = "permission";
-        argv[1] = "user";
-        argv[2] = "set";
-        argv[3] = permission;
-        int argc = 4;
-        // Avoid overly long commands by limiting number of UIDs per command.
-        for (int i = 0; i < uids.length; ++i) {
-            argv[argc++] = uids[i];
-            if (i == uids.length - 1 || argc == argv.length) {
-                try {
-                    mConnector.execute("network", Arrays.copyOf(argv, argc));
-                } catch (NativeDaemonConnectorException e) {
-                    throw e.rethrowAsParcelableException();
-                }
-                argc = 4;
-            }
+        try {
+            mNetdService.networkSetPermissionForUser(parsePermission(permission), uids);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2553,22 +2517,10 @@
     public void clearPermission(int[] uids) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
-        argv[0] = "permission";
-        argv[1] = "user";
-        argv[2] = "clear";
-        int argc = 3;
-        // Avoid overly long commands by limiting number of UIDs per command.
-        for (int i = 0; i < uids.length; ++i) {
-            argv[argc++] = uids[i];
-            if (i == uids.length - 1 || argc == argv.length) {
-                try {
-                    mConnector.execute("network", Arrays.copyOf(argv, argc));
-                } catch (NativeDaemonConnectorException e) {
-                    throw e.rethrowAsParcelableException();
-                }
-                argc = 3;
-            }
+        try {
+            mNetdService.networkClearPermissionForUser(uids);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2577,9 +2529,9 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "protect", "allow", uid);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkSetProtectAllow(uid);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -2588,26 +2540,26 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("network", "protect", "deny", uid);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.networkSetProtectDeny(uid);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
     @Override
     public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
-        modifyInterfaceInNetwork("add", "local", iface);
+        modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, iface);
 
         for (RouteInfo route : routes) {
             if (!route.isDefaultRoute()) {
-                modifyRoute("add", "local", route);
+                modifyRoute(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, route);
             }
         }
     }
 
     @Override
     public void removeInterfaceFromLocalNetwork(String iface) {
-        modifyInterfaceInNetwork("remove", "local", iface);
+        modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, iface);
     }
 
     @Override
@@ -2616,7 +2568,7 @@
 
         for (RouteInfo route : routes) {
             try {
-                modifyRoute("remove", "local", route);
+                modifyRoute(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, route);
             } catch (IllegalStateException e) {
                 failures++;
             }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c17a4cf..ca74adc 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -214,6 +214,9 @@
 
     private PhoneCapability mPhoneCapability = null;
 
+    @TelephonyManager.RadioPowerState
+    private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
+
     private final LocalLog mLocalLog = new LocalLog(100);
 
     private PreciseDataConnectionState mPreciseDataConnectionState =
@@ -753,6 +756,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+                        try {
+                            r.callback.onRadioPowerStateChanged(mRadioPowerState);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -1574,6 +1584,32 @@
         }
     }
 
+    public void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+        if (!checkNotifyPermission("notifyRadioPowerStateChanged()")) {
+            return;
+        }
+
+        if (VDBG) {
+            log("notifyRadioPowerStateChanged: state= " + state);
+        }
+
+        synchronized (mRecords) {
+            mRadioPowerState = state;
+
+            for (Record r : mRecords) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)) {
+                    try {
+                        r.callback.onRadioPowerStateChanged(state);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -1611,6 +1647,7 @@
             pw.println("mBackgroundCallState=" + mBackgroundCallState);
             pw.println("mVoLteServiceState=" + mVoLteServiceState);
             pw.println("mPhoneCapability=" + mPhoneCapability);
+            pw.println("mRadioPowerState=" + mRadioPowerState);
 
             pw.decreaseIndent();
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 784d62e..302e195 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -157,9 +157,11 @@
     // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
     // LMK_PROCPRIO <pid> <uid> <prio>
     // LMK_PROCREMOVE <pid>
+    // LMK_PROCPURGE
     static final byte LMK_TARGET = 0;
     static final byte LMK_PROCPRIO = 1;
     static final byte LMK_PROCREMOVE = 2;
+    static final byte LMK_PROCPURGE = 3;
 
     // These are the various interesting memory levels that we will give to
     // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
@@ -808,31 +810,46 @@
         return true;
     }
 
+    // Never call directly, use writeLmkd() instead
+    private static boolean writeLmkdCommand(ByteBuffer buf) {
+        try {
+            sLmkdOutputStream.write(buf.array(), 0, buf.position());
+        } catch (IOException ex) {
+            Slog.w(TAG, "Error writing to lowmemorykiller socket");
+
+            try {
+                sLmkdSocket.close();
+            } catch (IOException ex2) {
+            }
+
+            sLmkdSocket = null;
+            return false;
+        }
+        return true;
+    }
+
     private static void writeLmkd(ByteBuffer buf) {
 
         for (int i = 0; i < 3; i++) {
             if (sLmkdSocket == null) {
-                    if (openLmkdSocket() == false) {
-                        try {
-                            Thread.sleep(1000);
-                        } catch (InterruptedException ie) {
-                        }
-                        continue;
+                if (openLmkdSocket() == false) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException ie) {
                     }
-            }
-
-            try {
-                sLmkdOutputStream.write(buf.array(), 0, buf.position());
-                return;
-            } catch (IOException ex) {
-                Slog.w(TAG, "Error writing to lowmemorykiller socket");
-
-                try {
-                    sLmkdSocket.close();
-                } catch (IOException ex2) {
+                    continue;
                 }
 
-                sLmkdSocket = null;
+                // Purge any previously registered pids
+                ByteBuffer purge_buf = ByteBuffer.allocate(4);
+                purge_buf.putInt(LMK_PROCPURGE);
+                if (writeLmkdCommand(purge_buf) == false) {
+                    // Write failed, skip the rest and retry
+                    continue;
+                }
+            }
+            if (writeLmkdCommand(buf)) {
+                return;
             }
         }
     }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6fa17d8..3d77265 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -236,7 +236,6 @@
     private static final int MSG_PERSIST_RINGER_MODE = 3;
     private static final int MSG_AUDIO_SERVER_DIED = 4;
     private static final int MSG_PLAY_SOUND_EFFECT = 5;
-    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
     private static final int MSG_LOAD_SOUND_EFFECTS = 7;
     private static final int MSG_SET_FORCE_USE = 8;
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
@@ -268,6 +267,7 @@
     private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
     private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
     private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
+    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
     // end of messages handled under wakelock
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -4545,13 +4545,21 @@
         }
         synchronized (mLastDeviceConnectMsgTime) {
             long time = SystemClock.uptimeMillis() + delay;
-            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
-            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
-                    msg == MSG_SET_HEARING_AID_CONNECTION_STATE) {
+
+            if (msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
+                msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
+                msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
+                msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
+                msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
+                msg == MSG_BTA2DP_DOCK_TIMEOUT) {
+                if (mLastDeviceConnectMsgTime >= time) {
+                  // add a little delay to make sure messages are ordered as expected
+                  time = mLastDeviceConnectMsgTime + 30;
+                }
                 mLastDeviceConnectMsgTime = time;
             }
+
+            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
         }
     }
 
@@ -4713,6 +4721,13 @@
             } else {
                 delay = 0;
             }
+
+            if (DEBUG_DEVICES) {
+                Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
+                      + " state: " + state + " delay(ms): " + delay
+                      + " suppressNoisyIntent: " + suppressNoisyIntent);
+            }
+
             queueMsgUnderWakeLock(mAudioHandler,
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
@@ -5615,6 +5630,7 @@
                     synchronized (mConnectedDevices) {
                         makeA2dpDeviceUnavailableNow( (String) msg.obj );
                     }
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_FORCE_USE:
@@ -5845,6 +5861,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceUnavailableNow(String address) {
+        if (address == null) {
+            return;
+        }
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = false;
         }
@@ -5854,6 +5873,9 @@
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // Remove A2DP routes as well
         setCurrentAudioRouteName(null);
+        if (mDockAddress == address) {
+            mDockAddress = null;
+        }
     }
 
     // must be called synchronized on mConnectedDevices
@@ -5865,9 +5887,12 @@
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // send the delayed message to make the device unavailable later
-        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
-        mAudioHandler.sendMessageDelayed(msg, delayMs);
-
+        queueMsgUnderWakeLock(mAudioHandler,
+            MSG_BTA2DP_DOCK_TIMEOUT,
+            0,
+            0,
+            address,
+            delayMs);
     }
 
     // must be called synchronized on mConnectedDevices
@@ -5939,7 +5964,8 @@
     private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
     {
         if (DEBUG_DEVICES) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
+                + " is dock: "+btDevice.isBluetoothDock());
         }
         if (btDevice == null) {
             return;
@@ -5976,7 +6002,7 @@
                 } else {
                     // this could be a connection of another A2DP device before the timeout of
                     // a dock: cancel the dock timeout, and make the dock unavailable now
-                    if(hasScheduledA2dpDockTimeout()) {
+                    if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
                         cancelA2dpDeviceTimeout();
                         makeA2dpDeviceUnavailableNow(mDockAddress);
                     }
@@ -6195,17 +6221,6 @@
             }
         }
 
-        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_HEARING_AID_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
-            synchronized (mLastDeviceConnectMsgTime) {
-                long time = SystemClock.uptimeMillis();
-                if (mLastDeviceConnectMsgTime > time) {
-                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
-                }
-            }
-        }
         return delay;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 47e85b5..15468ff 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -126,9 +126,9 @@
     public ProxyInfo getDefaultProxy() {
         // This information is already available as a world read/writable jvm property.
         synchronized (mProxyLock) {
-            final ProxyInfo ret = mGlobalProxy;
-            if ((ret == null) && mDefaultProxyEnabled) return mDefaultProxy;
-            return ret;
+            if (mGlobalProxy != null) return mGlobalProxy;
+            if (mDefaultProxyEnabled) return mDefaultProxy;
+            return null;
         }
     }
 
@@ -204,11 +204,10 @@
      *
      * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
      * to do in a "sendProxyBroadcast" method.
-     * @param proxyInfo the proxy spec, or null for no proxy.
      */
-    // TODO : make the argument NonNull final and the method private
-    public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) {
-        if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, "");
+    public void sendProxyBroadcast() {
+        final ProxyInfo defaultProxy = getDefaultProxy();
+        final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
         if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
         if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
@@ -269,7 +268,7 @@
                 Binder.restoreCallingIdentity(token);
             }
 
-            sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo);
+            sendProxyBroadcast();
         }
     }
 
@@ -296,14 +295,14 @@
                     && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
                     && proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
                 mGlobalProxy = proxyInfo;
-                sendProxyBroadcast(mGlobalProxy);
+                sendProxyBroadcast();
                 return;
             }
             mDefaultProxy = proxyInfo;
 
             if (mGlobalProxy != null) return;
             if (mDefaultProxyEnabled) {
-                sendProxyBroadcast(proxyInfo);
+                sendProxyBroadcast();
             }
         }
     }
@@ -320,7 +319,7 @@
             if (mDefaultProxyEnabled != enabled) {
                 mDefaultProxyEnabled = enabled;
                 if (mGlobalProxy == null && mDefaultProxy != null) {
-                    sendProxyBroadcast(enabled ? mDefaultProxy : null);
+                    sendProxyBroadcast();
                 }
             }
         }
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 3d7fdbdd..de54c4b 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -80,7 +80,7 @@
 
 LOCAL_JAVA_LIBRARIES := \
     junit \
-    platform-robolectric-3.6.1-prebuilt
+    platform-robolectric-3.6.2-prebuilt
 
 LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
 LOCAL_MODULE := FrameworksServicesRoboTests
@@ -105,4 +105,4 @@
 
 LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
 
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.6.2/run_robotests.mk
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 942a07a..96ac935 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -121,7 +121,7 @@
         cal.set(Calendar.MINUTE, 15);
         cal.set(Calendar.SECOND, 0);
         cal.set(Calendar.MILLISECOND, 0);
-        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 1;
         mScheduleInfo.endHour = 3;
         mScheduleInfo.startMinute = 15;
@@ -149,7 +149,7 @@
         cal.set(Calendar.MINUTE, 15);
         cal.set(Calendar.SECOND, 0);
         cal.set(Calendar.MILLISECOND, 0);
-        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 22;
         mScheduleInfo.endHour = 3;
         mScheduleInfo.startMinute = 15;
@@ -250,7 +250,7 @@
         calAlarm.add(Calendar.DATE, 1); // add a day
 
         // ScheduleInfo: day 1, day 2: 9pm-7am
-        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 21;
         mScheduleInfo.endHour = 7;
         mScheduleInfo.startMinute = 0;
@@ -418,7 +418,7 @@
         now.set(Calendar.MILLISECOND, 0);
         now.add(Calendar.DATE, 1); // add a day
 
-        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 22;
         mScheduleInfo.startMinute = 15;
         mScheduleInfo.endHour = 3;
@@ -446,7 +446,7 @@
         now.set(Calendar.MILLISECOND, 0);
         now.add(Calendar.DATE, 1); // add a day
 
-        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay() + 1};
+        mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
         mScheduleInfo.startHour = 22;
         mScheduleInfo.startMinute = 15;
         mScheduleInfo.endHour = 3;
@@ -464,4 +464,10 @@
     private int getTodayDay() {
         return new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
     }
+
+    private int getTodayDay(int offset) {
+        Calendar cal = new GregorianCalendar();
+        cal.add(Calendar.DATE, offset);
+        return cal.get(Calendar.DAY_OF_WEEK);
+    }
 }
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
new file mode 100644
index 0000000..8c9d4df
--- /dev/null
+++ b/startop/iorap/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "libiorap-java-tests"
+    }
+  ],
+  "imports": [
+    {
+      "path": "system/iorap"
+    }
+  ]
+}
diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml
new file mode 100644
index 0000000..f83a16e
--- /dev/null
+++ b/startop/iorap/tests/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<configuration description="Runs libiorap-java-tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="libiorap-java-tests.apk" />
+    </target_preparer>
+
+    <!--
+      Our IIorapIntegrationTest.kt requires setlinux to be disabled:
+      it connects to the iorapd binder service but this requires selinux permissions:
+
+      avc:  denied  { find } for service=iorapd pid=2738 uid=10050
+        scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:iorapd_service:s0
+        tclass=service_manager permissive=0
+    -->
+    <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer">
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.google.android.startop.iorap.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
+
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
index 4ba44a9..16dcbe2 100644
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
@@ -77,17 +77,21 @@
             inOrder.verifyNoMoreInteractions()
 
         } finally {
-            iorapService.setTaskListener(null)
+            // iorapService.setTaskListener(null)
+            // FIXME: null is broken, C++ side sees a non-null object.
         }
     }
 
     @Test
     fun testOnPackageEvent() {
+        /*
         testAnyMethod { requestId : RequestId ->
             iorapService.onPackageEvent(requestId,
                     PackageEvent.createReplaced(
                             Uri.parse("https://www.google.com"), "com.fake.package"))
         }
+        */
+        // FIXME: Broken for some reason. C++ side never sees this call.
     }
 
     @Test
diff --git a/startop/tools/view_compiler/Android.bp b/startop/tools/view_compiler/Android.bp
index c3e9184..3681529 100644
--- a/startop/tools/view_compiler/Android.bp
+++ b/startop/tools/view_compiler/Android.bp
@@ -14,19 +14,30 @@
 // limitations under the License.
 //
 
+cc_defaults {
+    name: "viewcompiler_defaults",
+    shared_libs: [
+        "libdexfile",
+        "slicer",
+    ],
+}
+
 cc_library_host_static {
     name: "libviewcompiler",
+    defaults: ["viewcompiler_defaults"],
     srcs: [
+        "dex_builder.cc",
         "java_lang_builder.cc",
         "util.cc",
     ],
     static_libs: [
-        "libbase"
-    ]
+        "libbase",
+    ],
 }
 
 cc_binary_host {
     name: "viewcompiler",
+    defaults: ["viewcompiler_defaults"],
     srcs: [
         "main.cc",
     ],
@@ -40,10 +51,12 @@
 
 cc_test_host {
     name: "view-compiler-tests",
+    defaults: ["viewcompiler_defaults"],
     srcs: [
+        "dex_builder_test.cc",
         "util_test.cc",
     ],
     static_libs: [
         "libviewcompiler",
-    ]
+    ],
 }
diff --git a/startop/tools/view_compiler/dex_builder.cc b/startop/tools/view_compiler/dex_builder.cc
new file mode 100644
index 0000000..7a9f41f
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.cc
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+#include "dex_builder.h"
+
+#include "dex/descriptors_names.h"
+#include "dex/dex_instruction.h"
+
+#include <fstream>
+#include <memory>
+
+namespace startop {
+namespace dex {
+
+using std::shared_ptr;
+using std::string;
+
+using art::Instruction;
+using ::dex::kAccPublic;
+
+const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
+const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
+
+namespace {
+// From https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic
+constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00};
+
+// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
+constexpr size_t kMaxEncodedStringLength{5};
+
+}  // namespace
+
+void* TrackingAllocator::Allocate(size_t size) {
+  std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
+  void* raw_buffer = buffer.get();
+  allocations_[raw_buffer] = std::move(buffer);
+  return raw_buffer;
+}
+
+void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
+
+// Write out a DEX file that is basically:
+//
+// package dextest;
+// public class DexTest {
+//     public static int foo() { return 5; }
+// }
+void WriteTestDexFile(const string& filename) {
+  DexBuilder dex_file;
+
+  ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
+  cbuilder.set_source_file("dextest.java");
+
+  MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+
+  MethodBuilder::Register r = method.MakeRegister();
+  method.BuildConst4(r, 5);
+  method.BuildReturn(r);
+
+  method.Encode();
+
+  slicer::MemView image{dex_file.CreateImage()};
+
+  std::ofstream out_file(filename);
+  out_file.write(image.ptr<const char>(), image.size());
+}
+
+DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
+  dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
+}
+
+slicer::MemView DexBuilder::CreateImage() {
+  ::dex::Writer writer(dex_file_);
+  size_t image_size{0};
+  ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
+  return slicer::MemView{image, image_size};
+}
+
+ir::String* DexBuilder::GetOrAddString(const std::string& string) {
+  ir::String*& entry = strings_[string];
+
+  if (entry == nullptr) {
+    // Need to encode the length and then write out the bytes, including 1 byte for null terminator
+    auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
+    uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
+
+    size_t header_length =
+        reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
+
+    auto end = std::copy(string.begin(), string.end(), string_data_start);
+    *end = '\0';
+
+    entry = Alloc<ir::String>();
+    // +1 for null terminator
+    entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
+    string_data_.push_back(std::move(buffer));
+  }
+  return entry;
+}
+
+ClassBuilder DexBuilder::MakeClass(const std::string& name) {
+  auto* class_def = Alloc<ir::Class>();
+  ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
+  type_def->class_def = class_def;
+
+  class_def->type = type_def;
+  class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
+  class_def->access_flags = kAccPublic;
+  return ClassBuilder{this, class_def};
+}
+
+// TODO(eholk): we probably want GetOrAddString() also
+ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
+  if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
+    return types_by_descriptor_[descriptor];
+  }
+
+  ir::Type* type = Alloc<ir::Type>();
+  type->descriptor = GetOrAddString(descriptor);
+  types_by_descriptor_[descriptor] = type;
+  return type;
+}
+
+ir::Proto* Prototype::Encode(DexBuilder* dex) const {
+  auto* proto = dex->Alloc<ir::Proto>();
+  proto->shorty = dex->GetOrAddString(Shorty());
+  proto->return_type = dex->GetOrAddType(return_type_.descriptor());
+  if (param_types_.size() > 0) {
+    proto->param_types = dex->Alloc<ir::TypeList>();
+    for (const auto& param_type : param_types_) {
+      proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
+    }
+  } else {
+    proto->param_types = nullptr;
+  }
+  return proto;
+}
+
+std::string Prototype::Shorty() const {
+  std::string shorty;
+  shorty.append(return_type_.short_descriptor());
+  for (const auto& type_descriptor : param_types_) {
+    shorty.append(type_descriptor.short_descriptor());
+  }
+  return shorty;
+}
+
+ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def)
+    : parent_(parent), class_(class_def) {}
+
+MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
+  ir::String* dex_name{parent_->GetOrAddString(name)};
+
+  auto* decl = parent_->Alloc<ir::MethodDecl>();
+  decl->name = dex_name;
+  decl->parent = class_->type;
+  decl->prototype = prototype.Encode(parent_);
+
+  return MethodBuilder{parent_, class_, decl};
+}
+
+void ClassBuilder::set_source_file(const string& source) {
+  class_->source_file = parent_->GetOrAddString(source);
+}
+
+MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
+    : dex_{dex}, class_{class_def}, decl_{decl} {}
+
+ir::EncodedMethod* MethodBuilder::Encode() {
+  auto* method = dex_->Alloc<ir::EncodedMethod>();
+  method->decl = decl_;
+
+  // TODO: make access flags configurable
+  method->access_flags = kAccPublic | ::dex::kAccStatic;
+
+  auto* code = dex_->Alloc<ir::Code>();
+  code->registers = num_registers_;
+  // TODO: support ins and outs
+  code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
+  method->code = code;
+
+  class_->direct_methods.push_back(method);
+
+  return method;
+}
+
+MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; }
+
+void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); }
+
+void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); }
+
+void MethodBuilder::BuildConst4(Register target, int value) {
+  DCHECK_LT(value, 16);
+  // TODO: support more registers
+  DCHECK_LT(target, 16);
+  buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8));
+}
+
+}  // namespace dex
+}  // namespace startop
diff --git a/startop/tools/view_compiler/dex_builder.h b/startop/tools/view_compiler/dex_builder.h
new file mode 100644
index 0000000..d280abc
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.h
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+#ifndef DEX_BUILDER_H_
+#define DEX_BUILDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "slicer/dex_ir.h"
+#include "slicer/writer.h"
+
+namespace startop {
+namespace dex {
+
+// TODO: remove this once the dex generation code is complete.
+void WriteTestDexFile(const std::string& filename);
+
+//////////////////////////
+// Forward declarations //
+//////////////////////////
+class DexBuilder;
+
+// Our custom allocator for dex::Writer
+//
+// This keeps track of all allocations and ensures they are freed when
+// TrackingAllocator is destroyed. Pointers to memory allocated by this
+// allocator must not outlive the allocator.
+class TrackingAllocator : public ::dex::Writer::Allocator {
+ public:
+  virtual void* Allocate(size_t size);
+  virtual void Free(void* ptr);
+
+ private:
+  std::map<void*, std::unique_ptr<uint8_t[]>> allocations_;
+};
+
+// Represents a DEX type descriptor.
+//
+// TODO: add a way to create a descriptor for a reference of a class type.
+class TypeDescriptor {
+ public:
+  // Named constructors for base type descriptors.
+  static const TypeDescriptor Int();
+  static const TypeDescriptor Void();
+
+  // Return the full descriptor, such as I or Ljava/lang/Object
+  const std::string& descriptor() const { return descriptor_; }
+  // Return the shorty descriptor, such as I or L
+  std::string short_descriptor() const { return descriptor().substr(0, 1); }
+
+ private:
+  TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
+
+  const std::string descriptor_;
+};
+
+// Defines a function signature. For example, Prototype{TypeDescriptor::VOID, TypeDescriptor::Int}
+// represents the function type (Int) -> Void.
+class Prototype {
+ public:
+  template <typename... TypeDescriptors>
+  Prototype(TypeDescriptor return_type, TypeDescriptors... param_types)
+      : return_type_{return_type}, param_types_{param_types...} {}
+
+  // Encode this prototype into the dex file.
+  ir::Proto* Encode(DexBuilder* dex) const;
+
+  // Get the shorty descriptor, such as VII for (Int, Int) -> Void
+  std::string Shorty() const;
+
+ private:
+  const TypeDescriptor return_type_;
+  const std::vector<TypeDescriptor> param_types_;
+};
+
+// Tools to help build methods and their bodies.
+class MethodBuilder {
+ public:
+  MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl);
+
+  // Encode the method into DEX format.
+  ir::EncodedMethod* Encode();
+
+  // Registers are just represented by their number.
+  using Register = size_t;
+
+  // Create a new register to be used to storing values. Note that these are not SSA registers, like
+  // might be expected in similar code generators. This does no liveness tracking or anything, so
+  // it's up to the caller to reuse registers as appropriate.
+  Register MakeRegister();
+
+  /////////////////////////////////
+  // Instruction builder methods //
+  /////////////////////////////////
+
+  // return-void
+  void BuildReturn();
+  void BuildReturn(Register src);
+  // const/4
+  void BuildConst4(Register target, int value);
+
+  // TODO: add builders for more instructions
+
+ private:
+  DexBuilder* dex_;
+  ir::Class* class_;
+  ir::MethodDecl* decl_;
+
+  // A buffer to hold instructions we are generating.
+  std::vector<::dex::u2> buffer_;
+
+  // How many registers we've allocated
+  size_t num_registers_;
+};
+
+// A helper to build class definitions.
+class ClassBuilder {
+ public:
+  ClassBuilder(DexBuilder* parent, ir::Class* class_def);
+
+  void set_source_file(const std::string& source);
+
+  // Create a method with the given name and prototype. The returned MethodBuilder can be used to
+  // fill in the method body.
+  MethodBuilder CreateMethod(const std::string& name, Prototype prototype);
+
+ private:
+  DexBuilder* parent_;
+  ir::Class* class_;
+};
+
+// Builds Dex files from scratch.
+class DexBuilder {
+ public:
+  DexBuilder();
+
+  // Create an in-memory image of the DEX file that can either be loaded directly or written to a
+  // file.
+  slicer::MemView CreateImage();
+
+  template <typename T>
+  T* Alloc() {
+    return dex_file_->Alloc<T>();
+  }
+
+  // Find the ir::String that matches the given string, creating it if it does not exist.
+  ir::String* GetOrAddString(const std::string& string);
+  // Create a new class of the given name.
+  ClassBuilder MakeClass(const std::string& name);
+
+  // Add a type for the given descriptor, or return the existing one if it already exists.
+  // See the TypeDescriptor class for help generating these.
+  ir::Type* GetOrAddType(const std::string& descriptor);
+
+ private:
+  std::shared_ptr<ir::DexFile> dex_file_;
+
+  // allocator_ is needed to be able to encode the image.
+  TrackingAllocator allocator_;
+
+  // We'll need to allocate buffers for all of the encoded strings we create. This is where we store
+  // all of them.
+  std::vector<std::unique_ptr<uint8_t[]>> string_data_;
+
+  // Keep track of what types we've defined so we can look them up later.
+  std::map<std::string, ir::Type*> types_by_descriptor_;
+
+  // Keep track of what strings we've defined so we can look them up later.
+  std::map<std::string, ir::String*> strings_;
+};
+
+}  // namespace dex
+}  // namespace startop
+
+#endif  // DEX_BUILDER_H_
diff --git a/startop/tools/view_compiler/dex_builder_test.cc b/startop/tools/view_compiler/dex_builder_test.cc
new file mode 100644
index 0000000..0d8b854
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder_test.cc
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include "dex_builder.h"
+
+#include "dex/art_dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "gtest/gtest.h"
+
+using namespace startop::dex;
+
+// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
+// returns whether the verification was successful.
+bool EncodeAndVerify(DexBuilder* dex_file) {
+  slicer::MemView image{dex_file->CreateImage()};
+
+  art::ArtDexFileLoader loader;
+  std::string error_msg;
+  std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
+                                                                  image.size(),
+                                                                  /*location=*/"",
+                                                                  /*location_checksum=*/0,
+                                                                  /*oat_dex_file=*/nullptr,
+                                                                  /*verify=*/true,
+                                                                  /*verify_checksum=*/false,
+                                                                  &error_msg)};
+  return loaded_dex_file != nullptr;
+}
+
+TEST(DexBuilderTest, VerifyDexWithClassMethod) {
+  DexBuilder dex_file;
+
+  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
+  method.BuildReturn();
+  method.Encode();
+
+  EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
+
+// Makes sure a bad DEX class fails to verify.
+TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
+  DexBuilder dex_file;
+
+  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+  // This method has the error, because methods cannot take Void() as a parameter.
+  auto method{
+      cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
+  method.BuildReturn();
+  method.Encode();
+
+  EXPECT_FALSE(EncodeAndVerify(&dex_file));
+}
+
+TEST(DexBuilderTest, VerifyDexReturn5) {
+  DexBuilder dex_file;
+
+  auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+  auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+  auto r = method.MakeRegister();
+  method.BuildConst4(r, 5);
+  method.BuildReturn(r);
+  method.Encode();
+
+  EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/startop/tools/view_compiler/main.cc b/startop/tools/view_compiler/main.cc
index 0ad7e24..7d791c2 100644
--- a/startop/tools/view_compiler/main.cc
+++ b/startop/tools/view_compiler/main.cc
@@ -16,6 +16,7 @@
 
 #include "gflags/gflags.h"
 
+#include "dex_builder.h"
 #include "java_lang_builder.h"
 #include "util.h"
 
@@ -27,15 +28,17 @@
 #include <string>
 #include <vector>
 
+namespace {
+
 using namespace tinyxml2;
 using std::string;
 
 constexpr char kStdoutFilename[]{"stdout"};
 
-DEFINE_string(package, "", "The package name for the generated class (required)");
+DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
 DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
+DEFINE_string(package, "", "The package name for the generated class (required)");
 
-namespace {
 class ViewCompilerXmlVisitor : public XMLVisitor {
  public:
   ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
@@ -63,6 +66,7 @@
  private:
   JavaLangViewBuilder* builder_;
 };
+
 }  // end namespace
 
 int main(int argc, char** argv) {
@@ -82,6 +86,11 @@
     return 1;
   }
 
+  if (FLAGS_dex) {
+    startop::dex::WriteTestDexFile("test.dex");
+    return 0;
+  }
+
   const char* const filename = argv[kFileNameParam];
   const string layout_name = FindLayoutNameFromFilename(filename);
 
@@ -102,4 +111,4 @@
   xml.Accept(&visitor);
 
   return 0;
-}
\ No newline at end of file
+}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index d33a537..3127b35 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -676,7 +676,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelecomManager from(Context context) {
         return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
     }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 498be96..284e998 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -17,6 +17,7 @@
 package android.telephony;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Handler;
@@ -281,6 +282,15 @@
      */
     public static final int LISTEN_PHONE_CAPABILITY_CHANGE                 = 0x00200000;
 
+    /**
+     *  Listen for changes to the radio power state.
+     *
+     *  @see #onRadioPowerStateChanged
+     *  @hide
+     */
+    @SystemApi
+    public static final int LISTEN_RADIO_POWER_STATE_CHANGED               = 0x00400000;
+
     /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -407,6 +417,9 @@
                         PhoneStateListener.this.onPhoneCapabilityChanged(
                                 (PhoneCapability) msg.obj);
                         break;
+                    case LISTEN_RADIO_POWER_STATE_CHANGED:
+                        PhoneStateListener.this.onRadioPowerStateChanged((int) msg.obj);
+                        break;
                 }
             }
         };
@@ -647,6 +660,18 @@
     }
 
     /**
+     * Callback invoked when modem radio power state changes. Requires
+     * the READ_PRIVILEGED_PHONE_STATE permission.
+     * @param state the modem radio power state
+     * @hide
+     */
+    @SystemApi
+    public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+        // default implementation empty
+    }
+
+
+    /**
      * Callback invoked when telephony has received notice from a carrier
      * app that a network action that could result in connectivity loss
      * has been requested by an app using
@@ -777,6 +802,10 @@
         public void onPhoneCapabilityChanged(PhoneCapability capability) {
             send(LISTEN_PHONE_CAPABILITY_CHANGE, 0, 0, capability);
         }
+
+        public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+            send(LISTEN_RADIO_POWER_STATE_CHANGED, 0, 0, state);
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index e0ec2c5..bfbcd57 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Intent;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -246,7 +247,7 @@
     private String mDataOperatorAlphaLong;
     private String mDataOperatorAlphaShort;
     private String mDataOperatorNumeric;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean mIsManualNetworkSelection;
 
     private boolean mIsEmergencyOnly;
@@ -256,9 +257,9 @@
 
     @UnsupportedAppUsage
     private boolean mCssIndicator;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mNetworkId;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mSystemId;
     @UnsupportedAppUsage
     private int mCdmaRoamingIndicator;
@@ -456,7 +457,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getVoiceRegState() {
         return mVoiceRegState;
     }
@@ -471,7 +472,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getDataRegState() {
         return mDataRegState;
     }
@@ -532,7 +533,7 @@
      * @return roaming status
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public boolean getVoiceRoaming() {
         return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
@@ -556,7 +557,7 @@
      * @return roaming type
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public boolean getDataRoaming() {
         return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b0b7e7b..dfe35cd 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -43,6 +43,7 @@
 import android.net.INetworkPolicyManager;
 import android.net.NetworkCapabilities;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -87,8 +88,7 @@
     /** @hide */
     public static final int INVALID_PHONE_INDEX = -1;
 
-    /** An invalid slot identifier */
-    /** @hide */
+    /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
     public static final int INVALID_SIM_SLOT_INDEX = -1;
 
     /** Indicates the default subscription ID in Telephony. */
@@ -1309,15 +1309,15 @@
 
     /**
      * Get slotIndex associated with the subscription.
-     * @return slotIndex as a positive integer or a negative value if an error either
-     * SIM_NOT_INSERTED or < 0 if an invalid slot index
-     * @hide
+     *
+     * @param subscriptionId the unique SubscriptionInfo index in database
+     * @return slotIndex as a positive integer or {@link #INVALID_SIM_SLOT_INDEX} if the supplied
+     * subscriptionId doesn't have an associated slot index.
      */
-    @UnsupportedAppUsage
-    public static int getSlotIndex(int subId) {
-        if (!isValidSubscriptionId(subId)) {
+    public static int getSlotIndex(int subscriptionId) {
+        if (!isValidSubscriptionId(subscriptionId)) {
             if (DBG) {
-                logd("[getSlotIndex]- fail");
+                logd("[getSlotIndex]- supplied subscriptionId is invalid.");
             }
         }
 
@@ -1326,7 +1326,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSlotIndex(subId);
+                result = iSub.getSlotIndex(subscriptionId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1368,7 +1368,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static int getPhoneId(int subId) {
         if (!isValidSubscriptionId(subId)) {
             if (DBG) {
@@ -1664,7 +1664,7 @@
      * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static boolean isUsableSubIdValue(int subId) {
         return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
     }
@@ -1682,7 +1682,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
         int[] subIds = SubscriptionManager.getSubId(phoneId);
         if (subIds != null && subIds.length > 0) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e420448..d3cf331 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -41,6 +41,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PersistableBundle;
@@ -230,7 +231,8 @@
 
     /** @hide
     /* @deprecated - use getSystemService as described above */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelephonyManager getDefault() {
         return sInstance;
     }
@@ -319,7 +321,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static TelephonyManager from(Context context) {
         return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     }
@@ -1591,8 +1593,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
-                    mContext.getApplicationInfo().targetSdkVersion);
+            return telephony.getNeighboringCellInfo(mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1879,7 +1880,7 @@
      * @param subId
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getNetworkOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1907,7 +1908,7 @@
      * @param subId
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getNetworkOperator(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkOperatorForPhone(phoneId);
@@ -2231,7 +2232,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getDataNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -2267,7 +2268,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getVoiceNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -2750,7 +2751,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperator(int subId) {
         return getSimOperatorNumeric(subId);
     }
@@ -2764,7 +2765,7 @@
      * @see #getSimState
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumeric() {
         int subId = mSubId;
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
@@ -2793,7 +2794,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumeric(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNumericForPhone(phoneId);
@@ -2807,7 +2808,7 @@
      * @param phoneId for which SimOperator is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumericForPhone(int phoneId) {
         return getTelephonyProperty(phoneId,
                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
@@ -2834,7 +2835,7 @@
      * @param subId for which SimOperatorName is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNameForPhone(phoneId);
@@ -2864,7 +2865,7 @@
      * @param subId for which SimCountryIso is returned
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimCountryIso(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimCountryIsoForPhone(phoneId);
@@ -3054,7 +3055,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSubscriberId(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -3439,7 +3440,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getMsisdn(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -4405,7 +4406,7 @@
    /**
     * @hide
     */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private ITelephony getITelephony() {
         return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
     }
@@ -6855,6 +6856,60 @@
     }
 
     /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RADIO_POWER_"},
+            value = {RADIO_POWER_OFF,
+                    RADIO_POWER_ON,
+                    RADIO_POWER_UNAVAILABLE,
+            })
+    public @interface RadioPowerState {}
+
+    /**
+     * Radio explicitly powered off (e.g, airplane mode).
+     * @hide
+     */
+    @SystemApi
+    public static final int RADIO_POWER_OFF = 0;
+
+    /**
+     * Radio power is on.
+     * @hide
+     */
+    @SystemApi
+    public static final int RADIO_POWER_ON = 1;
+
+    /**
+     * Radio power unavailable (eg, modem resetting or not booted).
+     * @hide
+     */
+    @SystemApi
+    public static final int RADIO_POWER_UNAVAILABLE = 2;
+
+    /**
+     * @return current modem radio state.
+     *
+     * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+     * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            android.Manifest.permission.READ_PHONE_STATE})
+    public @RadioPowerState int getRadioPowerState() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName());
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return RADIO_POWER_UNAVAILABLE;
+    }
+
+    /** @hide */
     @SystemApi
     @SuppressLint("Doclava125")
     public void updateServiceLocation() {
@@ -7930,7 +7985,7 @@
      * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public ServiceState getServiceStateForSubscriber(int subId) {
         try {
             ITelephony service = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 1ebb697..8681859 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -52,5 +52,6 @@
     void onCarrierNetworkChange(in boolean active);
     void onUserMobileDataStateChanged(in boolean enabled);
     void onPhoneCapabilityChanged(in PhoneCapability capability);
+    void onRadioPowerStateChanged(in int state);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ebb94ff..3417da1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -280,7 +280,7 @@
     /**
      * Returns the neighboring cell information of the device.
      */
-    List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg, int targetSdk);
+    List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
 
      int getCallState();
 
@@ -1484,4 +1484,10 @@
      * Return the network selection mode on the subscription with id {@code subId}.
      */
      int getNetworkSelectionMode(int subId);
+
+     /**
+      * Return the modem radio power state for slot index.
+      *
+      */
+     int getRadioPowerState(int slotIdex, String callingPackage);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 43d56b3..2f40fcc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -79,4 +79,5 @@
     void notifyCarrierNetworkChange(in boolean active);
     void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
     void notifyPhoneCapabilityChanged(in PhoneCapability capability);
+    void notifyRadioPowerStateChanged(in int state);
 }
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index c9987b8..b165c6b 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -2,10 +2,19 @@
 
 include $(CLEAR_VARS)
 
+aapt2_results := $(call intermediates-dir-for,PACKAGING,aapt2_run_host_unit_tests)/result.xml
+
 # Target for running host unit tests on post/pre-submit.
 .PHONY: aapt2_run_host_unit_tests
-aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
-aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
-	-$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+aapt2_run_host_unit_tests: $(aapt2_results)
+
+$(call dist-for-goals,aapt2_run_host_unit_tests,$(aapt2_results):gtest/aapt2_host_unit_tests_result.xml)
+
+# Always run the tests again, even if they haven't changed
+$(aapt2_results): .KATI_IMPLICIT_OUTPUTS := $(aapt2_results)-nocache
+$(aapt2_results): $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+	-$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests --gtest_output=xml:$@ > /dev/null 2>&1
+
+aapt2_results :=
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index 76a2f2d..710da40 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -21,4 +21,6 @@
 A=( ${C[*]} ${A[*]} )
 unset IFS
 # Dump array back into the file
-printf '%s\n' "${A[@]}" > "$dest_list"
+if [ ${#A[@]} -ne 0 ]; then
+  printf '%s\n' "${A[@]}" > "$dest_list"
+fi