Merge "Fix hasUseBackgroundNetworksPermission issue."
diff --git a/Android.bp b/Android.bp
index 543e656..5f06a63 100644
--- a/Android.bp
+++ b/Android.bp
@@ -520,24 +520,22 @@
     name: "framework-javastream-protos",
     depfile: true,
 
-    tool_files: ["tools/genprotos.sh"],
     tools: [
         "aprotoc",
         "protoc-gen-javastream",
         "soong_zip",
     ],
 
-    // TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can
-    // end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to
-    // the way sbox rewrites the command. See b/70221552.
-    cmd: "$(location tools/genprotos.sh) " +
-        " $(location aprotoc) " +
-        " $(location protoc-gen-javastream) " +
-        " $(location soong_zip) " +
-        " $(genDir) " +
-        " $(depfile) " +
-        " $(in) " +
-        " $(out)",
+    cmd: "mkdir -p $(genDir)/$(in) " +
+        "&& $(location aprotoc) " +
+        "  --plugin=$(location protoc-gen-javastream) " +
+        "  --dependency_out=$(depfile) " +
+        "  --javastream_out=$(genDir)/$(in) " +
+        "  -Iexternal/protobuf/src " +
+        "  -I . " +
+        "  $(in) " +
+        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
     srcs: [
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
@@ -818,11 +816,13 @@
     srcs: [
         "core/java/android/os/HidlSupport.java",
         "core/java/android/annotation/IntDef.java",
+        "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/Nullable.java",
         "core/java/android/annotation/SystemApi.java",
         "core/java/android/annotation/TestApi.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
+        "core/java/android/os/HidlMemory.java",
         "core/java/android/os/HwBinder.java",
         "core/java/android/os/HwBlob.java",
         "core/java/android/os/HwParcel.java",
@@ -897,7 +897,10 @@
     "-overview $(location core/java/overview.html) " +
     // Federate Support Library references against local API file.
     "-federate SupportLib https://developer.android.com " +
-    "-federationapi SupportLib $(location :current-support-api) "
+    "-federationapi SupportLib $(location :current-support-api) " +
+    // Federate Support Library references against local API file.
+    "-federate AndroidX https://developer.android.com " +
+    "-federationapi AndroidX $(location :current-androidx-api) "
 
 framework_docs_only_libs = [
     "voip-common",
@@ -1015,6 +1018,7 @@
         "core/res/AndroidManifest.xml",
         "core/java/overview.html",
         ":current-support-api",
+        ":current-androidx-api",
     ],
     create_stubs: false,
 }
@@ -1034,6 +1038,7 @@
         ":core-current-stubs-source",
         ":core_public_api_files",
         ":updatable-media-srcs",
+        ":ike-api-srcs",
     ],
     libs: ["framework-internal-utils"],
     installable: false,
@@ -1356,8 +1361,10 @@
     srcs: [
         "core/java/android/os/HidlSupport.java",
         "core/java/android/annotation/IntDef.java",
+        "core/java/android/annotation/IntRange.java",
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/SystemApi.java",
+        "core/java/android/os/HidlMemory.java",
         "core/java/android/os/HwBinder.java",
         "core/java/android/os/HwBlob.java",
         "core/java/android/os/HwParcel.java",
diff --git a/api/current.txt b/api/current.txt
index ca692b0..5098324 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3021,9 +3021,9 @@
     field public final String type;
   }
 
-  public class AccountAuthenticatorActivity extends android.app.Activity {
-    ctor public AccountAuthenticatorActivity();
-    method public final void setAccountAuthenticatorResult(android.os.Bundle);
+  @Deprecated public class AccountAuthenticatorActivity extends android.app.Activity {
+    ctor @Deprecated public AccountAuthenticatorActivity();
+    method @Deprecated public final void setAccountAuthenticatorResult(android.os.Bundle);
   }
 
   public class AccountAuthenticatorResponse implements android.os.Parcelable {
@@ -4698,18 +4698,18 @@
     field public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3; // 0x3
   }
 
-  public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
-    ctor public ExpandableListActivity();
-    method public android.widget.ExpandableListAdapter getExpandableListAdapter();
-    method public android.widget.ExpandableListView getExpandableListView();
-    method public long getSelectedId();
-    method public long getSelectedPosition();
-    method public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
-    method public void onGroupCollapse(int);
-    method public void onGroupExpand(int);
-    method public void setListAdapter(android.widget.ExpandableListAdapter);
-    method public boolean setSelectedChild(int, int, boolean);
-    method public void setSelectedGroup(int);
+  @Deprecated public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
+    ctor @Deprecated public ExpandableListActivity();
+    method @Deprecated public android.widget.ExpandableListAdapter getExpandableListAdapter();
+    method @Deprecated public android.widget.ExpandableListView getExpandableListView();
+    method @Deprecated public long getSelectedId();
+    method @Deprecated public long getSelectedPosition();
+    method @Deprecated public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
+    method @Deprecated public void onGroupCollapse(int);
+    method @Deprecated public void onGroupExpand(int);
+    method @Deprecated public void setListAdapter(android.widget.ExpandableListAdapter);
+    method @Deprecated public boolean setSelectedChild(int, int, boolean);
+    method @Deprecated public void setSelectedGroup(int);
   }
 
   @Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
@@ -5151,40 +5151,40 @@
     method @Deprecated public void onKeyguardExitResult(boolean);
   }
 
-  public abstract class LauncherActivity extends android.app.ListActivity {
-    ctor public LauncherActivity();
-    method protected android.content.Intent getTargetIntent();
-    method protected android.content.Intent intentForPosition(int);
-    method protected android.app.LauncherActivity.ListItem itemForPosition(int);
-    method public java.util.List<android.app.LauncherActivity.ListItem> makeListItems();
-    method protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent);
-    method protected void onSetContentView();
+  @Deprecated public abstract class LauncherActivity extends android.app.ListActivity {
+    ctor @Deprecated public LauncherActivity();
+    method @Deprecated protected android.content.Intent getTargetIntent();
+    method @Deprecated protected android.content.Intent intentForPosition(int);
+    method @Deprecated protected android.app.LauncherActivity.ListItem itemForPosition(int);
+    method @Deprecated public java.util.List<android.app.LauncherActivity.ListItem> makeListItems();
+    method @Deprecated protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent);
+    method @Deprecated protected void onSetContentView();
   }
 
-  public class LauncherActivity.IconResizer {
-    ctor public LauncherActivity.IconResizer();
-    method public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable);
+  @Deprecated public class LauncherActivity.IconResizer {
+    ctor @Deprecated public LauncherActivity.IconResizer();
+    method @Deprecated public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable);
   }
 
-  public static class LauncherActivity.ListItem {
-    ctor public LauncherActivity.ListItem();
-    field public String className;
-    field public android.os.Bundle extras;
-    field public android.graphics.drawable.Drawable icon;
-    field public CharSequence label;
-    field public String packageName;
-    field public android.content.pm.ResolveInfo resolveInfo;
+  @Deprecated public static class LauncherActivity.ListItem {
+    ctor @Deprecated public LauncherActivity.ListItem();
+    field @Deprecated public String className;
+    field @Deprecated public android.os.Bundle extras;
+    field @Deprecated public android.graphics.drawable.Drawable icon;
+    field @Deprecated public CharSequence label;
+    field @Deprecated public String packageName;
+    field @Deprecated public android.content.pm.ResolveInfo resolveInfo;
   }
 
-  public class ListActivity extends android.app.Activity {
-    ctor public ListActivity();
-    method public android.widget.ListAdapter getListAdapter();
-    method public android.widget.ListView getListView();
-    method public long getSelectedItemId();
-    method public int getSelectedItemPosition();
-    method protected void onListItemClick(android.widget.ListView, android.view.View, int, long);
-    method public void setListAdapter(android.widget.ListAdapter);
-    method public void setSelection(int);
+  @Deprecated public class ListActivity extends android.app.Activity {
+    ctor @Deprecated public ListActivity();
+    method @Deprecated public android.widget.ListAdapter getListAdapter();
+    method @Deprecated public android.widget.ListView getListView();
+    method @Deprecated public long getSelectedItemId();
+    method @Deprecated public int getSelectedItemPosition();
+    method @Deprecated protected void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method @Deprecated public void setListAdapter(android.widget.ListAdapter);
+    method @Deprecated public void setSelection(int);
   }
 
   @Deprecated public class ListFragment extends android.app.Fragment {
@@ -5552,6 +5552,7 @@
     method @Deprecated public android.app.Notification.Builder setDefaults(int);
     method @NonNull public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
     method @NonNull public android.app.Notification.Builder setExtras(android.os.Bundle);
+    method @NonNull public android.app.Notification.Builder setFlag(int, boolean);
     method @NonNull public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
     method @NonNull public android.app.Notification.Builder setGroup(String);
     method @NonNull public android.app.Notification.Builder setGroupAlertBehavior(int);
@@ -9771,7 +9772,7 @@
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String);
     method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
     method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
-    method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -28935,14 +28936,17 @@
   }
 
   public class ProxyInfo implements android.os.Parcelable {
+    ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
     method public static android.net.ProxyInfo buildDirectProxy(String, int);
     method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
     method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+    method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
     method public int describeContents();
     method public String[] getExclusionList();
     method public String getHost();
     method public android.net.Uri getPacFileUrl();
     method public int getPort();
+    method public boolean isValid();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
   }
@@ -29891,6 +29895,7 @@
     field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
     field @Deprecated public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
     field @Deprecated public static final String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+    field public static final String UNKNOWN_SSID = "<unknown ssid>";
     field @Deprecated public static final int WIFI_MODE_FULL = 1; // 0x1
     field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
     field public static final int WIFI_MODE_FULL_LOW_LATENCY = 4; // 0x4
@@ -34535,8 +34540,8 @@
   }
 
   public final class FileUtils {
-    method public static void closeQuietly(@Nullable AutoCloseable);
-    method public static void closeQuietly(@Nullable java.io.FileDescriptor);
+    method @Deprecated public static void closeQuietly(@Nullable AutoCloseable);
+    method @Deprecated public static void closeQuietly(@Nullable java.io.FileDescriptor);
     method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream) throws java.io.IOException;
     method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException;
     method public static long copy(@NonNull java.io.FileDescriptor, @NonNull java.io.FileDescriptor) throws java.io.IOException;
@@ -34548,8 +34553,8 @@
   }
 
   public class Handler {
-    ctor public Handler();
-    ctor public Handler(@Nullable android.os.Handler.Callback);
+    ctor @Deprecated public Handler();
+    ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback);
     ctor public Handler(@NonNull android.os.Looper);
     ctor public Handler(@NonNull android.os.Looper, @Nullable android.os.Handler.Callback);
     method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper);
@@ -34673,7 +34678,7 @@
     method @Nullable public static android.os.Looper myLooper();
     method @NonNull public static android.os.MessageQueue myQueue();
     method public static void prepare();
-    method public static void prepareMainLooper();
+    method @Deprecated public static void prepareMainLooper();
     method public void quit();
     method public void quitSafely();
     method public void setMessageLogging(@Nullable android.util.Printer);
@@ -43520,6 +43525,7 @@
     field public static final int LOCAL = 2; // 0x2
     field public static final int MISSED = 5; // 0x5
     field public static final int OTHER = 9; // 0x9
+    field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
     field public static final int REJECTED = 6; // 0x6
     field public static final int REMOTE = 3; // 0x3
     field public static final int RESTRICTED = 8; // 0x8
@@ -44048,6 +44054,7 @@
     field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
     field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
     field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
+    field public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL = "allow_hold_call_during_emergency_bool";
     field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
     field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
     field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
@@ -48523,12 +48530,12 @@
     method @Nullable public static java.util.List<java.lang.String> getTimeZoneIdsForCountryCode(@NonNull String);
   }
 
-  public class TimingLogger {
-    ctor public TimingLogger(String, String);
-    method public void addSplit(String);
-    method public void dumpToLog();
-    method public void reset(String, String);
-    method public void reset();
+  @Deprecated public class TimingLogger {
+    ctor @Deprecated public TimingLogger(String, String);
+    method @Deprecated public void addSplit(String);
+    method @Deprecated public void dumpToLog();
+    method @Deprecated public void reset(String, String);
+    method @Deprecated public void reset();
   }
 
   public class TypedValue {
diff --git a/api/system-current.txt b/api/system-current.txt
index 34be264..0b8cdf2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -66,6 +66,7 @@
     field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
     field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
     field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
+    field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
     field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
@@ -74,6 +75,7 @@
     field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
     field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
     field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
+    field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES";
     field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
     field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
     field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
@@ -602,6 +604,15 @@
     method public boolean isStatusBarExpansionDisabled();
   }
 
+  public class UiModeManager {
+    method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
+    field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
+    field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
+    field public static final int DEFAULT_PRIORITY = 0; // 0x0
+    field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
+    field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
+  }
+
   public final class Vr2dDisplayProperties implements android.os.Parcelable {
     ctor public Vr2dDisplayProperties(int, int, int);
     method public int describeContents();
@@ -1300,7 +1311,23 @@
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
   }
 
+  public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
+    method protected void finalize();
+    method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+    method public boolean isTetheringOn();
+    method public void setBluetoothTethering(boolean);
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+    field public static final int LOCAL_NAP_ROLE = 1; // 0x1
+    field public static final int LOCAL_PANU_ROLE = 2; // 0x2
+    field public static final int PAN_ROLE_NONE = 0; // 0x0
+    field public static final int REMOTE_NAP_ROLE = 1; // 0x1
+    field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+  }
+
   public interface BluetoothProfile {
+    field public static final int PAN = 5; // 0x5
     field public static final int PRIORITY_OFF = 0; // 0x0
     field public static final int PRIORITY_ON = 100; // 0x64
   }
@@ -1355,8 +1382,9 @@
 
   public abstract class Context {
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean bindServiceAsUser(@RequiresPermission android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+    method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
     method public abstract android.content.Context createCredentialProtectedStorageContext();
-    method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract java.io.File getPreloadsFileCache();
     method public abstract boolean isCredentialProtectedStorage();
     method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
@@ -4052,6 +4080,33 @@
     method public void onUpstreamChanged(@Nullable android.net.Network);
   }
 
+  public final class IpConfiguration implements android.os.Parcelable {
+    ctor public IpConfiguration();
+    ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+    method @Nullable public android.net.ProxyInfo getHttpProxy();
+    method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+    method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+    method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
+    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+    method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
+    method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
+    method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
+  }
+
+  public enum IpConfiguration.IpAssignment {
+    enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
+    enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
+    enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
+  }
+
+  public enum IpConfiguration.ProxySettings {
+    enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
+  }
+
   public final class IpPrefix implements android.os.Parcelable {
     ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
@@ -4124,6 +4179,7 @@
 
   public class NetworkKey implements android.os.Parcelable {
     ctor public NetworkKey(android.net.WifiKey);
+    method @Nullable public static android.net.NetworkKey createFromScanResult(@Nullable android.net.wifi.ScanResult);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
@@ -4146,16 +4202,23 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException;
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException;
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage();
+    method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
+    method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public boolean requestScores(@NonNull android.net.NetworkKey[]) throws java.lang.SecurityException;
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
-    method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
-    field public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
+    method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
+    field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
     field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
     field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
     field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
-    field public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
-    field public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
+    field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
+    field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
     field public static final String EXTRA_NEW_SCORER = "newScorer";
-    field public static final String EXTRA_PACKAGE_NAME = "packageName";
+    field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
+  }
+
+  public static interface NetworkScoreManager.NetworkScoreCallback {
+    method public void clearScores();
+    method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>);
   }
 
   public class NetworkStack {
@@ -4277,6 +4340,258 @@
 
 }
 
+package android.net.eap {
+
+  public final class EapSessionConfig {
+  }
+
+  public static final class EapSessionConfig.Builder {
+    ctor public EapSessionConfig.Builder();
+    method @NonNull public android.net.eap.EapSessionConfig build();
+    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int);
+    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean);
+    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]);
+    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String);
+    method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int);
+  }
+
+  public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
+  }
+
+  public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig {
+    method public boolean allowsMismatchedNetworkNames();
+    method @NonNull public String getNetworkName();
+  }
+
+  public abstract static class EapSessionConfig.EapMethodConfig {
+    method public int getMethodType();
+  }
+
+  public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig {
+    method @NonNull public String getPassword();
+    method @NonNull public String getUsername();
+  }
+
+  public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig {
+  }
+
+  public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig {
+    method public int getAppType();
+    method public int getSubId();
+  }
+
+}
+
+package android.net.ipsec.ike {
+
+  public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal {
+  }
+
+  public static final class ChildSaProposal.Builder {
+    ctor public ChildSaProposal.Builder();
+    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int);
+    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int);
+    method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int);
+    method @NonNull public android.net.ipsec.ike.ChildSaProposal build();
+  }
+
+  public interface ChildSessionCallback {
+    method public void onClosed();
+    method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+    method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int);
+    method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int);
+    method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration);
+  }
+
+  public final class ChildSessionConfiguration {
+    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors();
+    method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses();
+    method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers();
+    method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers();
+    method @NonNull public java.util.List<android.net.LinkAddress> getInternalSubnets();
+    method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
+  }
+
+  public abstract class ChildSessionOptions {
+  }
+
+  public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
+    ctor public IkeFqdnIdentification(@NonNull String);
+    field @NonNull public final String fqdn;
+  }
+
+  public abstract class IkeIdentification {
+  }
+
+  public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+    ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address);
+    field @NonNull public final java.net.Inet4Address ipv4Address;
+  }
+
+  public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+    ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address);
+    field @NonNull public final java.net.Inet6Address ipv6Address;
+  }
+
+  public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification {
+    ctor public IkeKeyIdIdentification(@NonNull byte[]);
+    field @NonNull public final byte[] keyId;
+  }
+
+  public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification {
+    ctor public IkeRfc822AddrIdentification(@NonNull String);
+    field @NonNull public final String rfc822Name;
+  }
+
+  public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal {
+    method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions();
+  }
+
+  public static final class IkeSaProposal.Builder {
+    ctor public IkeSaProposal.Builder();
+    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int);
+    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int);
+    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int);
+    method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int);
+    method @NonNull public android.net.ipsec.ike.IkeSaProposal build();
+  }
+
+  public final class IkeSession implements java.lang.AutoCloseable {
+    ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+    method public void close();
+    method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
+    method public void kill();
+    method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+  }
+
+  public interface IkeSessionCallback {
+    method public void onClosed();
+    method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException);
+    method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException);
+    method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration);
+  }
+
+  public final class IkeSessionConfiguration {
+    ctor public IkeSessionConfiguration();
+    method @NonNull public String getRemoteApplicationVersion();
+    method public boolean isIkeExtensionEnabled(int);
+    field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1
+    field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
+  }
+
+  public final class IkeSessionOptions {
+  }
+
+  public static final class IkeSessionOptions.Builder {
+    ctor public IkeSessionOptions.Builder();
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions build();
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthPsk(@NonNull byte[]);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setServerAddress(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
+  }
+
+  public final class IkeTrafficSelector {
+    ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
+    field public final int endPort;
+    field @NonNull public final java.net.InetAddress endingAddress;
+    field public final int startPort;
+    field @NonNull public final java.net.InetAddress startingAddress;
+  }
+
+  public abstract class SaProposal {
+    method @NonNull public java.util.List<java.lang.Integer> getDhGroups();
+    method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms();
+    method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms();
+    field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
+    field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
+    field public static final int DH_GROUP_NONE = 0; // 0x0
+    field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3
+    field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
+    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13
+    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14
+    field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12
+    field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
+    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
+    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
+    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
+    field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
+    field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
+    field public static final int KEY_LEN_AES_128 = 128; // 0x80
+    field public static final int KEY_LEN_AES_192 = 192; // 0xc0
+    field public static final int KEY_LEN_AES_256 = 256; // 0x100
+    field public static final int KEY_LEN_UNUSED = 0; // 0x0
+    field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
+    field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
+  }
+
+  public final class TransportModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+  }
+
+  public static final class TransportModeChildSessionOptions.Builder {
+    ctor public TransportModeChildSessionOptions.Builder();
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions build();
+  }
+
+  public final class TunnelModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+  }
+
+  public static final class TunnelModeChildSessionOptions.Builder {
+    ctor public TunnelModeChildSessionOptions.Builder();
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalSubnetRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions build();
+  }
+
+}
+
+package android.net.ipsec.ike.exceptions {
+
+  public abstract class IkeException extends java.lang.Exception {
+  }
+
+  public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException {
+  }
+
+  public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException {
+    method @Nullable public byte[] getErrorData();
+    method public int getErrorType();
+    field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18
+    field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c
+    field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25
+    field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24
+    field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4
+    field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11
+    field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5
+    field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9
+    field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27
+    field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7
+    field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23
+    field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe
+    field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22
+    field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b
+    field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26
+    field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1
+  }
+
+}
+
 package android.net.metrics {
 
   public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -4708,7 +5023,7 @@
     method public boolean isPortableHotspotSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
-    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback, @Nullable java.util.concurrent.Executor);
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
@@ -5207,6 +5522,17 @@
     method @NonNull public static java.io.File getVendorDirectory();
   }
 
+  public class HidlMemory implements java.io.Closeable {
+    ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+    method public void close() throws java.io.IOException;
+    method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+    method protected void finalize();
+    method @Nullable public android.os.NativeHandle getHandle();
+    method @NonNull public String getName();
+    method public long getSize();
+    method @NonNull public android.os.NativeHandle releaseHandle();
+  }
+
   public class HidlSupport {
     method public static boolean deepEquals(Object, Object);
     method public static int deepHashCode(Object);
@@ -5237,6 +5563,7 @@
     method public final void copyToInt8Array(long, byte[], int);
     method public final boolean getBool(long);
     method public final double getDouble(long);
+    method public final long getFieldHandle(long);
     method public final float getFloat(long);
     method public final short getInt16(long);
     method public final int getInt32(long);
@@ -5251,6 +5578,7 @@
     method public final void putDoubleArray(long, double[]);
     method public final void putFloat(long, float);
     method public final void putFloatArray(long, float[]);
+    method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
     method public final void putInt16(long, short);
     method public final void putInt16Array(long, short[]);
     method public final void putInt32(long, int);
@@ -5279,9 +5607,11 @@
     method public final double readDouble();
     method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
     method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+    method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
     method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
     method public final float readFloat();
     method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+    method @NonNull public final android.os.HidlMemory readHidlMemory();
     method public final short readInt16();
     method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
     method public final int readInt32();
@@ -5306,6 +5636,7 @@
     method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
     method public final void writeFloat(float);
     method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+    method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
     method public final void writeInt16(short);
     method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
     method public final void writeInt32(int);
@@ -7314,6 +7645,21 @@
     method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
   }
 
+  public class CbGeoUtils {
+  }
+
+  public static interface CbGeoUtils.Geometry {
+    method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
+  }
+
+  public static class CbGeoUtils.LatLng {
+    ctor public CbGeoUtils.LatLng(double, double);
+    method public double distance(@NonNull android.telephony.CbGeoUtils.LatLng);
+    method @NonNull public android.telephony.CbGeoUtils.LatLng subtract(@NonNull android.telephony.CbGeoUtils.LatLng);
+    field public final double lat;
+    field public final double lng;
+  }
+
   public abstract class CellBroadcastService extends android.app.Service {
     ctor public CellBroadcastService();
     method @CallSuper @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -7737,6 +8083,7 @@
     field public static final int NUMBER_UNREACHABLE = 8; // 0x8
     field public static final int OTASP_PROVISIONING_IN_PROCESS = 76; // 0x4c
     field public static final int OUTGOING_CANCELED = 44; // 0x2c
+    field public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80; // 0x50
     field public static final int OUTGOING_FAILURE = 43; // 0x2b
     field public static final int OUT_OF_NETWORK = 11; // 0xb
     field public static final int OUT_OF_SERVICE = 18; // 0x12
@@ -7751,6 +8098,14 @@
     field public static final int WIFI_LOST = 59; // 0x3b
   }
 
+  public final class ImsiEncryptionInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getKeyIdentifier();
+    method @Nullable public java.security.PublicKey getPublicKey();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR;
+  }
+
   public final class LteVopsSupportInfo implements android.os.Parcelable {
     ctor public LteVopsSupportInfo(int, int);
     method public int describeContents();
@@ -8106,6 +8461,7 @@
   }
 
   public final class SmsCbLocation implements android.os.Parcelable {
+    ctor public SmsCbLocation(@NonNull String, int, int);
     method public int describeContents();
     method public int getCid();
     method public int getLac();
@@ -8117,7 +8473,7 @@
   }
 
   public final class SmsCbMessage implements android.os.Parcelable {
-    ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int);
+    ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int);
     method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor);
     method public int describeContents();
     method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo();
@@ -8126,6 +8482,7 @@
     method public int getGeographicalScope();
     method @Nullable public String getLanguageCode();
     method @NonNull public android.telephony.SmsCbLocation getLocation();
+    method public int getMaximumWaitingDuration();
     method @Nullable public String getMessageBody();
     method public int getMessageFormat();
     method public int getMessagePriority();
@@ -8143,6 +8500,7 @@
     field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; // 0x0
     field public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; // 0x2
     field public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; // 0x1
+    field public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; // 0xff
     field public static final int MESSAGE_FORMAT_3GPP = 1; // 0x1
     field public static final int MESSAGE_FORMAT_3GPP2 = 2; // 0x2
     field public static final int MESSAGE_PRIORITY_EMERGENCY = 3; // 0x3
@@ -8228,6 +8586,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
@@ -8277,13 +8636,14 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetherApnRequired();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
     method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -8321,6 +8681,8 @@
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+    field public static final int KEY_TYPE_EPDG = 1; // 0x1
+    field public static final int KEY_TYPE_WLAN = 2; // 0x2
     field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
     field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
     field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
@@ -8902,7 +9264,7 @@
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
diff --git a/api/test-current.txt b/api/test-current.txt
index 14210e3..d59d15a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -376,6 +376,7 @@
   }
 
   public class UiModeManager {
+    method @RequiresPermission("android.permission.ENTER_CAR_MODE_PRIORITIZED") public void enableCarMode(@IntRange(from=0) int, int);
     method public boolean isNightModeLocked();
     method public boolean isUiModeLocked();
   }
@@ -639,7 +640,8 @@
   }
 
   public abstract class Context {
-    method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
+    method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.view.Display getDisplay();
     method public abstract int getDisplayId();
     method public android.os.UserHandle getUser();
@@ -692,6 +694,7 @@
     method public void setEnableRollback(boolean);
     method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+    method public void setRequestDowngrade(boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
 
@@ -793,6 +796,7 @@
   }
 
   public final class RollbackManager {
+    method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void blockRollbackManager(long);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
@@ -1722,6 +1726,17 @@
     method public static boolean contains(java.io.File, java.io.File);
   }
 
+  public class HidlMemory implements java.io.Closeable {
+    ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+    method public void close() throws java.io.IOException;
+    method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+    method protected void finalize();
+    method @Nullable public android.os.NativeHandle getHandle();
+    method @NonNull public String getName();
+    method public long getSize();
+    method @NonNull public android.os.NativeHandle releaseHandle();
+  }
+
   public abstract class HwBinder implements android.os.IHwBinder {
     ctor public HwBinder();
     method public static final void configureRpcThreadpool(long, boolean);
@@ -1745,6 +1760,7 @@
     method public final void copyToInt8Array(long, byte[], int);
     method public final boolean getBool(long);
     method public final double getDouble(long);
+    method public final long getFieldHandle(long);
     method public final float getFloat(long);
     method public final short getInt16(long);
     method public final int getInt32(long);
@@ -1759,6 +1775,7 @@
     method public final void putDoubleArray(long, double[]);
     method public final void putFloat(long, float);
     method public final void putFloatArray(long, float[]);
+    method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
     method public final void putInt16(long, short);
     method public final void putInt16Array(long, short[]);
     method public final void putInt32(long, int);
@@ -1787,9 +1804,11 @@
     method public final double readDouble();
     method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
     method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+    method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
     method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
     method public final float readFloat();
     method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+    method @NonNull public final android.os.HidlMemory readHidlMemory();
     method public final short readInt16();
     method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
     method public final int readInt32();
@@ -1814,6 +1833,7 @@
     method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
     method public final void writeFloat(float);
     method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+    method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
     method public final void writeInt16(short);
     method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
     method public final void writeInt32(int);
@@ -3230,7 +3250,7 @@
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting();
diff --git a/config/OWNERS b/config/OWNERS
new file mode 100644
index 0000000..53f80e6
--- /dev/null
+++ b/config/OWNERS
@@ -0,0 +1,5 @@
+# compat-team@ for changes to hiddenapi files
+per-file hiddenapi-* = andreionea@google.com, atrost@google.com, mathewi@google.com, satayev@google.com
+
+# Escalations:
+per-file hiddenapi-* = bdc@google.com, narayan@google.com
\ No newline at end of file
diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-greylist-max-q.txt
new file mode 100644
index 0000000..f465604
--- /dev/null
+++ b/config/hiddenapi-greylist-max-q.txt
@@ -0,0 +1,704 @@
+Landroid/R$styleable;->ActionBar:[I
+Landroid/R$styleable;->ActionBar_background:I
+Landroid/R$styleable;->ActionBar_backgroundSplit:I
+Landroid/R$styleable;->ActionBar_backgroundStacked:I
+Landroid/R$styleable;->ActionBar_divider:I
+Landroid/R$styleable;->ActionBar_itemPadding:I
+Landroid/R$styleable;->CalendarView:[I
+Landroid/R$styleable;->CalendarView_dateTextAppearance:I
+Landroid/R$styleable;->CalendarView_firstDayOfWeek:I
+Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I
+Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I
+Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I
+Landroid/R$styleable;->CalendarView_shownWeekCount:I
+Landroid/R$styleable;->CalendarView_showWeekNumber:I
+Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I
+Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I
+Landroid/R$styleable;->CalendarView_weekNumberColor:I
+Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I
+Landroid/R$styleable;->CheckBoxPreference:[I
+Landroid/R$styleable;->CheckedTextView:[I
+Landroid/R$styleable;->CheckedTextView_checkMark:I
+Landroid/R$styleable;->CompoundButton:[I
+Landroid/R$styleable;->CompoundButton_button:I
+Landroid/R$styleable;->ContactsDataKind:[I
+Landroid/R$styleable;->DatePicker:[I
+Landroid/R$styleable;->DialogPreference:[I
+Landroid/R$styleable;->DrawableStates:[I
+Landroid/R$styleable;->ExpandableListView:[I
+Landroid/R$styleable;->FrameLayout_Layout:[I
+Landroid/R$styleable;->HorizontalScrollView:[I
+Landroid/R$styleable;->ImageView:[I
+Landroid/R$styleable;->ImageView_adjustViewBounds:I
+Landroid/R$styleable;->ImageView_baselineAlignBottom:I
+Landroid/R$styleable;->ImageView_cropToPadding:I
+Landroid/R$styleable;->ImageView_maxHeight:I
+Landroid/R$styleable;->ImageView_maxWidth:I
+Landroid/R$styleable;->ImageView_scaleType:I
+Landroid/R$styleable;->ImageView_src:I
+Landroid/R$styleable;->ImageView_tint:I
+Landroid/R$styleable;->Keyboard:[I
+Landroid/R$styleable;->Keyboard_horizontalGap:I
+Landroid/R$styleable;->Keyboard_Key:[I
+Landroid/R$styleable;->Keyboard_keyHeight:I
+Landroid/R$styleable;->Keyboard_keyWidth:I
+Landroid/R$styleable;->Keyboard_Key_codes:I
+Landroid/R$styleable;->Keyboard_Key_iconPreview:I
+Landroid/R$styleable;->Keyboard_Key_isModifier:I
+Landroid/R$styleable;->Keyboard_Key_isRepeatable:I
+Landroid/R$styleable;->Keyboard_Key_isSticky:I
+Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I
+Landroid/R$styleable;->Keyboard_Key_keyIcon:I
+Landroid/R$styleable;->Keyboard_Key_keyLabel:I
+Landroid/R$styleable;->Keyboard_Key_keyOutputText:I
+Landroid/R$styleable;->Keyboard_Key_popupCharacters:I
+Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I
+Landroid/R$styleable;->Keyboard_Row:[I
+Landroid/R$styleable;->Keyboard_Row_keyboardMode:I
+Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I
+Landroid/R$styleable;->Keyboard_verticalGap:I
+Landroid/R$styleable;->LinearLayout:[I
+Landroid/R$styleable;->LinearLayout_baselineAligned:I
+Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I
+Landroid/R$styleable;->LinearLayout_divider:I
+Landroid/R$styleable;->LinearLayout_dividerPadding:I
+Landroid/R$styleable;->LinearLayout_gravity:I
+Landroid/R$styleable;->LinearLayout_Layout:[I
+Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_height:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I
+Landroid/R$styleable;->LinearLayout_Layout_layout_width:I
+Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I
+Landroid/R$styleable;->LinearLayout_orientation:I
+Landroid/R$styleable;->LinearLayout_showDividers:I
+Landroid/R$styleable;->ListView:[I
+Landroid/R$styleable;->ListView_divider:I
+Landroid/R$styleable;->ListView_dividerHeight:I
+Landroid/R$styleable;->LockPatternView:[I
+Landroid/R$styleable;->NumberPicker:[I
+Landroid/R$styleable;->NumberPicker_solidColor:I
+Landroid/R$styleable;->PopupWindow:[I
+Landroid/R$styleable;->ProgressBar:[I
+Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I
+Landroid/R$styleable;->ProgressBar_indeterminateDuration:I
+Landroid/R$styleable;->ProgressBar_maxHeight:I
+Landroid/R$styleable;->ProgressBar_maxWidth:I
+Landroid/R$styleable;->ProgressBar_minHeight:I
+Landroid/R$styleable;->ProgressBar_minWidth:I
+Landroid/R$styleable;->ProgressBar_progressDrawable:I
+Landroid/R$styleable;->RingtonePreference:[I
+Landroid/R$styleable;->ScrollView:[I
+Landroid/R$styleable;->SearchView:[I
+Landroid/R$styleable;->SeekBar:[I
+Landroid/R$styleable;->SeekBar_thumb:I
+Landroid/R$styleable;->SeekBar_thumbOffset:I
+Landroid/R$styleable;->SlidingDrawer:[I
+Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I
+Landroid/R$styleable;->SlidingDrawer_animateOnClick:I
+Landroid/R$styleable;->SlidingDrawer_bottomOffset:I
+Landroid/R$styleable;->SlidingDrawer_content:I
+Landroid/R$styleable;->SlidingDrawer_handle:I
+Landroid/R$styleable;->SlidingDrawer_orientation:I
+Landroid/R$styleable;->SlidingDrawer_topOffset:I
+Landroid/R$styleable;->Switch:[I
+Landroid/R$styleable;->Switch_showText:I
+Landroid/R$styleable;->Switch_splitTrack:I
+Landroid/R$styleable;->Switch_switchMinWidth:I
+Landroid/R$styleable;->Switch_switchPadding:I
+Landroid/R$styleable;->Switch_switchTextAppearance:I
+Landroid/R$styleable;->Switch_textOff:I
+Landroid/R$styleable;->Switch_textOn:I
+Landroid/R$styleable;->Switch_thumb:I
+Landroid/R$styleable;->Switch_thumbTextPadding:I
+Landroid/R$styleable;->Switch_track:I
+Landroid/R$styleable;->TextAppearance:[I
+Landroid/R$styleable;->TextAppearance_textAllCaps:I
+Landroid/R$styleable;->TextAppearance_textColor:I
+Landroid/R$styleable;->TextAppearance_textColorHighlight:I
+Landroid/R$styleable;->TextAppearance_textColorHint:I
+Landroid/R$styleable;->TextAppearance_textColorLink:I
+Landroid/R$styleable;->TextAppearance_textSize:I
+Landroid/R$styleable;->TextAppearance_textStyle:I
+Landroid/R$styleable;->TextAppearance_typeface:I
+Landroid/R$styleable;->TextView:[I
+Landroid/R$styleable;->TextView_autoLink:I
+Landroid/R$styleable;->TextView_autoText:I
+Landroid/R$styleable;->TextView_bufferType:I
+Landroid/R$styleable;->TextView_capitalize:I
+Landroid/R$styleable;->TextView_cursorVisible:I
+Landroid/R$styleable;->TextView_digits:I
+Landroid/R$styleable;->TextView_drawableBottom:I
+Landroid/R$styleable;->TextView_drawableEnd:I
+Landroid/R$styleable;->TextView_drawableLeft:I
+Landroid/R$styleable;->TextView_drawablePadding:I
+Landroid/R$styleable;->TextView_drawableRight:I
+Landroid/R$styleable;->TextView_drawableStart:I
+Landroid/R$styleable;->TextView_drawableTop:I
+Landroid/R$styleable;->TextView_editable:I
+Landroid/R$styleable;->TextView_ellipsize:I
+Landroid/R$styleable;->TextView_ems:I
+Landroid/R$styleable;->TextView_enabled:I
+Landroid/R$styleable;->TextView_freezesText:I
+Landroid/R$styleable;->TextView_gravity:I
+Landroid/R$styleable;->TextView_height:I
+Landroid/R$styleable;->TextView_hint:I
+Landroid/R$styleable;->TextView_imeActionId:I
+Landroid/R$styleable;->TextView_imeActionLabel:I
+Landroid/R$styleable;->TextView_imeOptions:I
+Landroid/R$styleable;->TextView_includeFontPadding:I
+Landroid/R$styleable;->TextView_inputMethod:I
+Landroid/R$styleable;->TextView_inputType:I
+Landroid/R$styleable;->TextView_lines:I
+Landroid/R$styleable;->TextView_lineSpacingExtra:I
+Landroid/R$styleable;->TextView_lineSpacingMultiplier:I
+Landroid/R$styleable;->TextView_linksClickable:I
+Landroid/R$styleable;->TextView_marqueeRepeatLimit:I
+Landroid/R$styleable;->TextView_maxEms:I
+Landroid/R$styleable;->TextView_maxHeight:I
+Landroid/R$styleable;->TextView_maxLength:I
+Landroid/R$styleable;->TextView_maxLines:I
+Landroid/R$styleable;->TextView_maxWidth:I
+Landroid/R$styleable;->TextView_minEms:I
+Landroid/R$styleable;->TextView_minHeight:I
+Landroid/R$styleable;->TextView_minLines:I
+Landroid/R$styleable;->TextView_minWidth:I
+Landroid/R$styleable;->TextView_numeric:I
+Landroid/R$styleable;->TextView_password:I
+Landroid/R$styleable;->TextView_phoneNumber:I
+Landroid/R$styleable;->TextView_privateImeOptions:I
+Landroid/R$styleable;->TextView_scrollHorizontally:I
+Landroid/R$styleable;->TextView_selectAllOnFocus:I
+Landroid/R$styleable;->TextView_shadowColor:I
+Landroid/R$styleable;->TextView_shadowDx:I
+Landroid/R$styleable;->TextView_shadowDy:I
+Landroid/R$styleable;->TextView_shadowRadius:I
+Landroid/R$styleable;->TextView_singleLine:I
+Landroid/R$styleable;->TextView_text:I
+Landroid/R$styleable;->TextView_textAllCaps:I
+Landroid/R$styleable;->TextView_textAppearance:I
+Landroid/R$styleable;->TextView_textColor:I
+Landroid/R$styleable;->TextView_textColorHighlight:I
+Landroid/R$styleable;->TextView_textColorHint:I
+Landroid/R$styleable;->TextView_textColorLink:I
+Landroid/R$styleable;->TextView_textCursorDrawable:I
+Landroid/R$styleable;->TextView_textIsSelectable:I
+Landroid/R$styleable;->TextView_textScaleX:I
+Landroid/R$styleable;->TextView_textSelectHandle:I
+Landroid/R$styleable;->TextView_textSelectHandleLeft:I
+Landroid/R$styleable;->TextView_textSelectHandleRight:I
+Landroid/R$styleable;->TextView_textSize:I
+Landroid/R$styleable;->TextView_textStyle:I
+Landroid/R$styleable;->TextView_typeface:I
+Landroid/R$styleable;->TextView_width:I
+Landroid/R$styleable;->Theme:[I
+Landroid/R$styleable;->View:[I
+Landroid/R$styleable;->ViewDrawableStates:[I
+Landroid/R$styleable;->ViewGroup_Layout:[I
+Landroid/R$styleable;->ViewGroup_Layout_layout_height:I
+Landroid/R$styleable;->ViewGroup_Layout_layout_width:I
+Landroid/R$styleable;->ViewGroup_MarginLayout:[I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I
+Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I
+Landroid/R$styleable;->View_alpha:I
+Landroid/R$styleable;->View_background:I
+Landroid/R$styleable;->View_clickable:I
+Landroid/R$styleable;->View_contentDescription:I
+Landroid/R$styleable;->View_drawingCacheQuality:I
+Landroid/R$styleable;->View_duplicateParentState:I
+Landroid/R$styleable;->View_fadingEdge:I
+Landroid/R$styleable;->View_filterTouchesWhenObscured:I
+Landroid/R$styleable;->View_fitsSystemWindows:I
+Landroid/R$styleable;->View_focusable:I
+Landroid/R$styleable;->View_focusableInTouchMode:I
+Landroid/R$styleable;->View_hapticFeedbackEnabled:I
+Landroid/R$styleable;->View_id:I
+Landroid/R$styleable;->View_isScrollContainer:I
+Landroid/R$styleable;->View_keepScreenOn:I
+Landroid/R$styleable;->View_longClickable:I
+Landroid/R$styleable;->View_minHeight:I
+Landroid/R$styleable;->View_minWidth:I
+Landroid/R$styleable;->View_nextFocusDown:I
+Landroid/R$styleable;->View_nextFocusLeft:I
+Landroid/R$styleable;->View_nextFocusRight:I
+Landroid/R$styleable;->View_nextFocusUp:I
+Landroid/R$styleable;->View_onClick:I
+Landroid/R$styleable;->View_overScrollMode:I
+Landroid/R$styleable;->View_padding:I
+Landroid/R$styleable;->View_paddingBottom:I
+Landroid/R$styleable;->View_paddingEnd:I
+Landroid/R$styleable;->View_paddingLeft:I
+Landroid/R$styleable;->View_paddingRight:I
+Landroid/R$styleable;->View_paddingStart:I
+Landroid/R$styleable;->View_paddingTop:I
+Landroid/R$styleable;->View_rotation:I
+Landroid/R$styleable;->View_rotationX:I
+Landroid/R$styleable;->View_rotationY:I
+Landroid/R$styleable;->View_saveEnabled:I
+Landroid/R$styleable;->View_scaleX:I
+Landroid/R$styleable;->View_scaleY:I
+Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I
+Landroid/R$styleable;->View_scrollbarFadeDuration:I
+Landroid/R$styleable;->View_scrollbars:I
+Landroid/R$styleable;->View_scrollbarSize:I
+Landroid/R$styleable;->View_scrollbarStyle:I
+Landroid/R$styleable;->View_scrollbarThumbHorizontal:I
+Landroid/R$styleable;->View_scrollbarThumbVertical:I
+Landroid/R$styleable;->View_scrollbarTrackHorizontal:I
+Landroid/R$styleable;->View_scrollbarTrackVertical:I
+Landroid/R$styleable;->View_scrollX:I
+Landroid/R$styleable;->View_scrollY:I
+Landroid/R$styleable;->View_soundEffectsEnabled:I
+Landroid/R$styleable;->View_tag:I
+Landroid/R$styleable;->View_transformPivotX:I
+Landroid/R$styleable;->View_transformPivotY:I
+Landroid/R$styleable;->View_translationX:I
+Landroid/R$styleable;->View_translationY:I
+Landroid/R$styleable;->View_visibility:I
+Landroid/R$styleable;->Window:[I
+Landroid/R$styleable;->Window_windowBackground:I
+Landroid/R$styleable;->Window_windowFrame:I
+Lcom/android/internal/R$anim;->fade_in:I
+Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
+Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
+Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I
+Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I
+Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I
+Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I
+Lcom/android/internal/R$array;->config_tether_upstream_types:I
+Lcom/android/internal/R$array;->config_tether_usb_regexs:I
+Lcom/android/internal/R$array;->config_tether_wifi_regexs:I
+Lcom/android/internal/R$array;->maps_starting_lat_lng:I
+Lcom/android/internal/R$array;->maps_starting_zoom:I
+Lcom/android/internal/R$attr;->actionBarStyle:I
+Lcom/android/internal/R$attr;->buttonStyle:I
+Lcom/android/internal/R$attr;->description:I
+Lcom/android/internal/R$attr;->editTextStyle:I
+Lcom/android/internal/R$attr;->mapViewStyle:I
+Lcom/android/internal/R$attr;->popupWindowStyle:I
+Lcom/android/internal/R$attr;->state_above_anchor:I
+Lcom/android/internal/R$attr;->state_focused:I
+Lcom/android/internal/R$attr;->state_pressed:I
+Lcom/android/internal/R$attr;->state_selected:I
+Lcom/android/internal/R$attr;->switchStyle:I
+Lcom/android/internal/R$attr;->text:I
+Lcom/android/internal/R$attr;->title:I
+Lcom/android/internal/R$attr;->webViewStyle:I
+Lcom/android/internal/R$bool;-><init>()V
+Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
+Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
+Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
+Lcom/android/internal/R$bool;->config_showNavigationBar:I
+Lcom/android/internal/R$dimen;-><init>()V
+Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I
+Lcom/android/internal/R$dimen;->navigation_bar_height:I
+Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I
+Lcom/android/internal/R$dimen;->navigation_bar_width:I
+Lcom/android/internal/R$dimen;->status_bar_height:I
+Lcom/android/internal/R$dimen;->toast_y_offset:I
+Lcom/android/internal/R$drawable;->btn_check_off:I
+Lcom/android/internal/R$drawable;->compass_arrow:I
+Lcom/android/internal/R$drawable;->compass_base:I
+Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I
+Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I
+Lcom/android/internal/R$drawable;->loading_tile_android:I
+Lcom/android/internal/R$drawable;->maps_google_logo:I
+Lcom/android/internal/R$drawable;->no_tile_256:I
+Lcom/android/internal/R$drawable;->reticle:I
+Lcom/android/internal/R$drawable;->stat_sys_download:I
+Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I
+Lcom/android/internal/R$id;->account_name:I
+Lcom/android/internal/R$id;->account_type:I
+Lcom/android/internal/R$id;->alertTitle:I
+Lcom/android/internal/R$id;->allow_button:I
+Lcom/android/internal/R$id;->amPm:I
+Lcom/android/internal/R$id;->authtoken_type:I
+Lcom/android/internal/R$id;->background:I
+Lcom/android/internal/R$id;->back_button:I
+Lcom/android/internal/R$id;->body:I
+Lcom/android/internal/R$id;->buttonPanel:I
+Lcom/android/internal/R$id;->camera:I
+Lcom/android/internal/R$id;->cancel:I
+Lcom/android/internal/R$id;->clip_children_set_tag:I
+Lcom/android/internal/R$id;->clip_children_tag:I
+Lcom/android/internal/R$id;->clip_to_padding_tag:I
+Lcom/android/internal/R$id;->closeButton:I
+Lcom/android/internal/R$id;->content:I
+Lcom/android/internal/R$id;->contentPanel:I
+Lcom/android/internal/R$id;->custom:I
+Lcom/android/internal/R$id;->customPanel:I
+Lcom/android/internal/R$id;->datePicker:I
+Lcom/android/internal/R$id;->day:I
+Lcom/android/internal/R$id;->deny_button:I
+Lcom/android/internal/R$id;->description:I
+Lcom/android/internal/R$id;->edit:I
+Lcom/android/internal/R$id;->edittext_container:I
+Lcom/android/internal/R$id;->find_next:I
+Lcom/android/internal/R$id;->find_prev:I
+Lcom/android/internal/R$id;->icon:I
+Lcom/android/internal/R$id;->keyboard:I
+Lcom/android/internal/R$id;->keyboardView:I
+Lcom/android/internal/R$id;->line1:I
+Lcom/android/internal/R$id;->list_item:I
+Lcom/android/internal/R$id;->matches:I
+Lcom/android/internal/R$id;->mediacontroller_progress:I
+Lcom/android/internal/R$id;->media_actions:I
+Lcom/android/internal/R$id;->message:I
+Lcom/android/internal/R$id;->minute:I
+Lcom/android/internal/R$id;->month:I
+Lcom/android/internal/R$id;->name:I
+Lcom/android/internal/R$id;->notification_header:I
+Lcom/android/internal/R$id;->ok:I
+Lcom/android/internal/R$id;->overlay:I
+Lcom/android/internal/R$id;->packages_list:I
+Lcom/android/internal/R$id;->package_label:I
+Lcom/android/internal/R$id;->parentPanel:I
+Lcom/android/internal/R$id;->pause:I
+Lcom/android/internal/R$id;->pending_intent_tag:I
+Lcom/android/internal/R$id;->progress:I
+Lcom/android/internal/R$id;->redo:I
+Lcom/android/internal/R$id;->remote_input_tag:I
+Lcom/android/internal/R$id;->right_icon:I
+Lcom/android/internal/R$id;->search_src_text:I
+Lcom/android/internal/R$id;->share:I
+Lcom/android/internal/R$id;->shortcut:I
+Lcom/android/internal/R$id;->status_bar_latest_event_content:I
+Lcom/android/internal/R$id;->tabcontent:I
+Lcom/android/internal/R$id;->tabs:I
+Lcom/android/internal/R$id;->text1:I
+Lcom/android/internal/R$id;->text2:I
+Lcom/android/internal/R$id;->text:I
+Lcom/android/internal/R$id;->time:I
+Lcom/android/internal/R$id;->timePicker:I
+Lcom/android/internal/R$id;->time_current:I
+Lcom/android/internal/R$id;->title:I
+Lcom/android/internal/R$id;->titleDivider:I
+Lcom/android/internal/R$id;->titleDividerTop:I
+Lcom/android/internal/R$id;->title_container:I
+Lcom/android/internal/R$id;->title_template:I
+Lcom/android/internal/R$id;->topPanel:I
+Lcom/android/internal/R$id;->up:I
+Lcom/android/internal/R$id;->year:I
+Lcom/android/internal/R$id;->zoomControls:I
+Lcom/android/internal/R$id;->zoomMagnify:I
+Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
+Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I
+Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I
+Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
+Lcom/android/internal/R$interpolator;->accelerate_cubic:I
+Lcom/android/internal/R$interpolator;->decelerate_cubic:I
+Lcom/android/internal/R$layout;->notification_template_material_base:I
+Lcom/android/internal/R$layout;->preference_header_item:I
+Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$layout;->select_dialog:I
+Lcom/android/internal/R$layout;->select_dialog_multichoice:I
+Lcom/android/internal/R$layout;->select_dialog_singlechoice:I
+Lcom/android/internal/R$layout;->webview_find:I
+Lcom/android/internal/R$layout;->zoom_magnify:I
+Lcom/android/internal/R$plurals;->matches_found:I
+Lcom/android/internal/R$raw;->loaderror:I
+Lcom/android/internal/R$raw;->nodomain:I
+Lcom/android/internal/R$string;->byteShort:I
+Lcom/android/internal/R$string;->cancel:I
+Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I
+Lcom/android/internal/R$string;->gigabyteShort:I
+Lcom/android/internal/R$string;->kilobyteShort:I
+Lcom/android/internal/R$string;->map:I
+Lcom/android/internal/R$string;->megabyteShort:I
+Lcom/android/internal/R$string;->notification_title:I
+Lcom/android/internal/R$string;->no_matches:I
+Lcom/android/internal/R$string;->ok:I
+Lcom/android/internal/R$string;->petabyteShort:I
+Lcom/android/internal/R$string;->redo:I
+Lcom/android/internal/R$string;->share:I
+Lcom/android/internal/R$string;->terabyteShort:I
+Lcom/android/internal/R$string;->whichApplication:I
+Lcom/android/internal/R$style;->Animation_DropDownDown:I
+Lcom/android/internal/R$style;->Animation_DropDownUp:I
+Lcom/android/internal/R$style;->Animation_PopupWindow:I
+Lcom/android/internal/R$style;->Theme:I
+Lcom/android/internal/R$style;->Theme_Dialog_Alert:I
+Lcom/android/internal/R$style;->Theme_Holo_Light:I
+Lcom/android/internal/R$style;->Theme_Light:I
+Lcom/android/internal/R$styleable;-><init>()V
+Lcom/android/internal/R$styleable;->AbsListView:[I
+Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I
+Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I
+Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I
+Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView_listSelector:I
+Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I
+Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I
+Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I
+Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I
+Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I
+Lcom/android/internal/R$styleable;->AbsSpinner:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
+Lcom/android/internal/R$styleable;->ActionMode:[I
+Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I
+Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I
+Lcom/android/internal/R$styleable;->AlertDialog:[I
+Lcom/android/internal/R$styleable;->AnalogClock:[I
+Lcom/android/internal/R$styleable;->AndroidManifest:[I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
+Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
+Lcom/android/internal/R$styleable;->AndroidManifestData:[I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
+Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
+Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
+Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I
+Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I
+Lcom/android/internal/R$styleable;->AndroidManifestService:[I
+Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
+Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I
+Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
+Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I
+Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I
+Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I
+Lcom/android/internal/R$styleable;->CheckBoxPreference:[I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I
+Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
+Lcom/android/internal/R$styleable;->CheckedTextView:[I
+Lcom/android/internal/R$styleable;->CheckedTextView_checked:I
+Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I
+Lcom/android/internal/R$styleable;->CompoundButton:[I
+Lcom/android/internal/R$styleable;->CompoundButton_button:I
+Lcom/android/internal/R$styleable;->CompoundButton_checked:I
+Lcom/android/internal/R$styleable;->ContactsDataKind:[I
+Lcom/android/internal/R$styleable;->DatePicker:[I
+Lcom/android/internal/R$styleable;->DialogPreference:[I
+Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
+Lcom/android/internal/R$styleable;->Dream:[I
+Lcom/android/internal/R$styleable;->EdgeEffect:[I
+Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
+Lcom/android/internal/R$styleable;->FastScroll:[I
+Lcom/android/internal/R$styleable;->FrameLayout:[I
+Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I
+Lcom/android/internal/R$styleable;->Gallery:[I
+Lcom/android/internal/R$styleable;->GridView:[I
+Lcom/android/internal/R$styleable;->IconMenuView:[I
+Lcom/android/internal/R$styleable;->ImageView:[I
+Lcom/android/internal/R$styleable;->ImageView_scaleType:I
+Lcom/android/internal/R$styleable;->ImageView_src:I
+Lcom/android/internal/R$styleable;->Keyboard:[I
+Lcom/android/internal/R$styleable;->KeyboardView:[I
+Lcom/android/internal/R$styleable;->Keyboard_Key:[I
+Lcom/android/internal/R$styleable;->Keyboard_Row:[I
+Lcom/android/internal/R$styleable;->ListPreference:[I
+Lcom/android/internal/R$styleable;->ListPreference_entries:I
+Lcom/android/internal/R$styleable;->ListView:[I
+Lcom/android/internal/R$styleable;->ListView_divider:I
+Lcom/android/internal/R$styleable;->ListView_dividerHeight:I
+Lcom/android/internal/R$styleable;->ListView_entries:I
+Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I
+Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I
+Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I
+Lcom/android/internal/R$styleable;->MapView:[I
+Lcom/android/internal/R$styleable;->MapView_apiKey:I
+Lcom/android/internal/R$styleable;->MenuGroup:[I
+Lcom/android/internal/R$styleable;->MenuItem:[I
+Lcom/android/internal/R$styleable;->NumberPicker:[I
+Lcom/android/internal/R$styleable;->PopupWindow:[I
+Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
+Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I
+Lcom/android/internal/R$styleable;->Preference:[I
+Lcom/android/internal/R$styleable;->PreferenceGroup:[I
+Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I
+Lcom/android/internal/R$styleable;->Preference_defaultValue:I
+Lcom/android/internal/R$styleable;->Preference_dependency:I
+Lcom/android/internal/R$styleable;->Preference_enabled:I
+Lcom/android/internal/R$styleable;->Preference_fragment:I
+Lcom/android/internal/R$styleable;->Preference_icon:I
+Lcom/android/internal/R$styleable;->Preference_key:I
+Lcom/android/internal/R$styleable;->Preference_layout:I
+Lcom/android/internal/R$styleable;->Preference_order:I
+Lcom/android/internal/R$styleable;->Preference_persistent:I
+Lcom/android/internal/R$styleable;->Preference_selectable:I
+Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I
+Lcom/android/internal/R$styleable;->Preference_summary:I
+Lcom/android/internal/R$styleable;->Preference_title:I
+Lcom/android/internal/R$styleable;->Preference_widgetLayout:I
+Lcom/android/internal/R$styleable;->ProgressBar:[I
+Lcom/android/internal/R$styleable;->QuickContactBadge:[I
+Lcom/android/internal/R$styleable;->RingtonePreference:[I
+Lcom/android/internal/R$styleable;->ScrollView:[I
+Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
+Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I
+Lcom/android/internal/R$styleable;->Switch:[I
+Lcom/android/internal/R$styleable;->SwitchPreference:[I
+Lcom/android/internal/R$styleable;->SyncAdapter:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
+Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
+Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
+Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
+Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
+Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
+Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
+Lcom/android/internal/R$styleable;->TabWidget:[I
+Lcom/android/internal/R$styleable;->TextAppearance:[I
+Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I
+Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColor:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I
+Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I
+Lcom/android/internal/R$styleable;->TextAppearance_textSize:I
+Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I
+Lcom/android/internal/R$styleable;->TextAppearance_typeface:I
+Lcom/android/internal/R$styleable;->TextClock:[I
+Lcom/android/internal/R$styleable;->TextView:[I
+Lcom/android/internal/R$styleable;->TextViewAppearance:[I
+Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I
+Lcom/android/internal/R$styleable;->TextView_autoLink:I
+Lcom/android/internal/R$styleable;->TextView_autoText:I
+Lcom/android/internal/R$styleable;->TextView_bufferType:I
+Lcom/android/internal/R$styleable;->TextView_capitalize:I
+Lcom/android/internal/R$styleable;->TextView_cursorVisible:I
+Lcom/android/internal/R$styleable;->TextView_digits:I
+Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
+Lcom/android/internal/R$styleable;->TextView_drawableEnd:I
+Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
+Lcom/android/internal/R$styleable;->TextView_drawablePadding:I
+Lcom/android/internal/R$styleable;->TextView_drawableRight:I
+Lcom/android/internal/R$styleable;->TextView_drawableStart:I
+Lcom/android/internal/R$styleable;->TextView_drawableTop:I
+Lcom/android/internal/R$styleable;->TextView_editable:I
+Lcom/android/internal/R$styleable;->TextView_editorExtras:I
+Lcom/android/internal/R$styleable;->TextView_ellipsize:I
+Lcom/android/internal/R$styleable;->TextView_ems:I
+Lcom/android/internal/R$styleable;->TextView_enabled:I
+Lcom/android/internal/R$styleable;->TextView_freezesText:I
+Lcom/android/internal/R$styleable;->TextView_gravity:I
+Lcom/android/internal/R$styleable;->TextView_height:I
+Lcom/android/internal/R$styleable;->TextView_hint:I
+Lcom/android/internal/R$styleable;->TextView_imeActionId:I
+Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I
+Lcom/android/internal/R$styleable;->TextView_imeOptions:I
+Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I
+Lcom/android/internal/R$styleable;->TextView_inputMethod:I
+Lcom/android/internal/R$styleable;->TextView_inputType:I
+Lcom/android/internal/R$styleable;->TextView_lines:I
+Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I
+Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I
+Lcom/android/internal/R$styleable;->TextView_linksClickable:I
+Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I
+Lcom/android/internal/R$styleable;->TextView_maxEms:I
+Lcom/android/internal/R$styleable;->TextView_maxHeight:I
+Lcom/android/internal/R$styleable;->TextView_maxLength:I
+Lcom/android/internal/R$styleable;->TextView_maxLines:I
+Lcom/android/internal/R$styleable;->TextView_maxWidth:I
+Lcom/android/internal/R$styleable;->TextView_minEms:I
+Lcom/android/internal/R$styleable;->TextView_minHeight:I
+Lcom/android/internal/R$styleable;->TextView_minLines:I
+Lcom/android/internal/R$styleable;->TextView_minWidth:I
+Lcom/android/internal/R$styleable;->TextView_numeric:I
+Lcom/android/internal/R$styleable;->TextView_password:I
+Lcom/android/internal/R$styleable;->TextView_phoneNumber:I
+Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I
+Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I
+Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I
+Lcom/android/internal/R$styleable;->TextView_shadowColor:I
+Lcom/android/internal/R$styleable;->TextView_shadowDx:I
+Lcom/android/internal/R$styleable;->TextView_shadowDy:I
+Lcom/android/internal/R$styleable;->TextView_shadowRadius:I
+Lcom/android/internal/R$styleable;->TextView_singleLine:I
+Lcom/android/internal/R$styleable;->TextView_text:I
+Lcom/android/internal/R$styleable;->TextView_textAllCaps:I
+Lcom/android/internal/R$styleable;->TextView_textAppearance:I
+Lcom/android/internal/R$styleable;->TextView_textColor:I
+Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I
+Lcom/android/internal/R$styleable;->TextView_textColorHint:I
+Lcom/android/internal/R$styleable;->TextView_textColorLink:I
+Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I
+Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I
+Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I
+Lcom/android/internal/R$styleable;->TextView_textScaleX:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I
+Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I
+Lcom/android/internal/R$styleable;->TextView_textSize:I
+Lcom/android/internal/R$styleable;->TextView_textStyle:I
+Lcom/android/internal/R$styleable;->TextView_typeface:I
+Lcom/android/internal/R$styleable;->TextView_width:I
+Lcom/android/internal/R$styleable;->Theme:[I
+Lcom/android/internal/R$styleable;->TwoLineListItem:[I
+Lcom/android/internal/R$styleable;->View:[I
+Lcom/android/internal/R$styleable;->ViewAnimator:[I
+Lcom/android/internal/R$styleable;->ViewFlipper:[I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
+Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I
+Lcom/android/internal/R$styleable;->ViewStub:[I
+Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
+Lcom/android/internal/R$styleable;->ViewStub_layout:I
+Lcom/android/internal/R$styleable;->View_background:I
+Lcom/android/internal/R$styleable;->View_clickable:I
+Lcom/android/internal/R$styleable;->View_focusable:I
+Lcom/android/internal/R$styleable;->View_id:I
+Lcom/android/internal/R$styleable;->View_longClickable:I
+Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I
+Lcom/android/internal/R$styleable;->Window:[I
+Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowBackground:I
+Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
+Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
+Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
+Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
+Lcom/android/internal/R$xml;->power_profile:I
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 2d3394b..52caa42 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -238,270 +238,6 @@
 Landroid/os/storage/IObbActionListener$Stub;-><init>()V
 Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
-Landroid/R$styleable;->ActionBar:[I
-Landroid/R$styleable;->ActionBar_background:I
-Landroid/R$styleable;->ActionBar_backgroundSplit:I
-Landroid/R$styleable;->ActionBar_backgroundStacked:I
-Landroid/R$styleable;->ActionBar_divider:I
-Landroid/R$styleable;->ActionBar_itemPadding:I
-Landroid/R$styleable;->CalendarView:[I
-Landroid/R$styleable;->CalendarView_dateTextAppearance:I
-Landroid/R$styleable;->CalendarView_firstDayOfWeek:I
-Landroid/R$styleable;->CalendarView_focusedMonthDateColor:I
-Landroid/R$styleable;->CalendarView_selectedDateVerticalBar:I
-Landroid/R$styleable;->CalendarView_selectedWeekBackgroundColor:I
-Landroid/R$styleable;->CalendarView_shownWeekCount:I
-Landroid/R$styleable;->CalendarView_showWeekNumber:I
-Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I
-Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I
-Landroid/R$styleable;->CalendarView_weekNumberColor:I
-Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I
-Landroid/R$styleable;->CheckBoxPreference:[I
-Landroid/R$styleable;->CheckedTextView:[I
-Landroid/R$styleable;->CheckedTextView_checkMark:I
-Landroid/R$styleable;->CompoundButton:[I
-Landroid/R$styleable;->CompoundButton_button:I
-Landroid/R$styleable;->ContactsDataKind:[I
-Landroid/R$styleable;->DatePicker:[I
-Landroid/R$styleable;->DialogPreference:[I
-Landroid/R$styleable;->DrawableStates:[I
-Landroid/R$styleable;->ExpandableListView:[I
-Landroid/R$styleable;->FrameLayout_Layout:[I
-Landroid/R$styleable;->HorizontalScrollView:[I
-Landroid/R$styleable;->ImageView:[I
-Landroid/R$styleable;->ImageView_adjustViewBounds:I
-Landroid/R$styleable;->ImageView_baselineAlignBottom:I
-Landroid/R$styleable;->ImageView_cropToPadding:I
-Landroid/R$styleable;->ImageView_maxHeight:I
-Landroid/R$styleable;->ImageView_maxWidth:I
-Landroid/R$styleable;->ImageView_scaleType:I
-Landroid/R$styleable;->ImageView_src:I
-Landroid/R$styleable;->ImageView_tint:I
-Landroid/R$styleable;->Keyboard:[I
-Landroid/R$styleable;->Keyboard_horizontalGap:I
-Landroid/R$styleable;->Keyboard_Key:[I
-Landroid/R$styleable;->Keyboard_keyHeight:I
-Landroid/R$styleable;->Keyboard_keyWidth:I
-Landroid/R$styleable;->Keyboard_Key_codes:I
-Landroid/R$styleable;->Keyboard_Key_iconPreview:I
-Landroid/R$styleable;->Keyboard_Key_isModifier:I
-Landroid/R$styleable;->Keyboard_Key_isRepeatable:I
-Landroid/R$styleable;->Keyboard_Key_isSticky:I
-Landroid/R$styleable;->Keyboard_Key_keyEdgeFlags:I
-Landroid/R$styleable;->Keyboard_Key_keyIcon:I
-Landroid/R$styleable;->Keyboard_Key_keyLabel:I
-Landroid/R$styleable;->Keyboard_Key_keyOutputText:I
-Landroid/R$styleable;->Keyboard_Key_popupCharacters:I
-Landroid/R$styleable;->Keyboard_Key_popupKeyboard:I
-Landroid/R$styleable;->Keyboard_Row:[I
-Landroid/R$styleable;->Keyboard_Row_keyboardMode:I
-Landroid/R$styleable;->Keyboard_Row_rowEdgeFlags:I
-Landroid/R$styleable;->Keyboard_verticalGap:I
-Landroid/R$styleable;->LinearLayout:[I
-Landroid/R$styleable;->LinearLayout_baselineAligned:I
-Landroid/R$styleable;->LinearLayout_baselineAlignedChildIndex:I
-Landroid/R$styleable;->LinearLayout_divider:I
-Landroid/R$styleable;->LinearLayout_dividerPadding:I
-Landroid/R$styleable;->LinearLayout_gravity:I
-Landroid/R$styleable;->LinearLayout_Layout:[I
-Landroid/R$styleable;->LinearLayout_Layout_layout_gravity:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_height:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_weight:I
-Landroid/R$styleable;->LinearLayout_Layout_layout_width:I
-Landroid/R$styleable;->LinearLayout_measureWithLargestChild:I
-Landroid/R$styleable;->LinearLayout_orientation:I
-Landroid/R$styleable;->LinearLayout_showDividers:I
-Landroid/R$styleable;->ListView:[I
-Landroid/R$styleable;->ListView_divider:I
-Landroid/R$styleable;->ListView_dividerHeight:I
-Landroid/R$styleable;->LockPatternView:[I
-Landroid/R$styleable;->NumberPicker:[I
-Landroid/R$styleable;->NumberPicker_solidColor:I
-Landroid/R$styleable;->PopupWindow:[I
-Landroid/R$styleable;->ProgressBar:[I
-Landroid/R$styleable;->ProgressBar_indeterminateDrawable:I
-Landroid/R$styleable;->ProgressBar_indeterminateDuration:I
-Landroid/R$styleable;->ProgressBar_maxHeight:I
-Landroid/R$styleable;->ProgressBar_maxWidth:I
-Landroid/R$styleable;->ProgressBar_minHeight:I
-Landroid/R$styleable;->ProgressBar_minWidth:I
-Landroid/R$styleable;->ProgressBar_progressDrawable:I
-Landroid/R$styleable;->RingtonePreference:[I
-Landroid/R$styleable;->ScrollView:[I
-Landroid/R$styleable;->SearchView:[I
-Landroid/R$styleable;->SeekBar:[I
-Landroid/R$styleable;->SeekBar_thumb:I
-Landroid/R$styleable;->SeekBar_thumbOffset:I
-Landroid/R$styleable;->SlidingDrawer:[I
-Landroid/R$styleable;->SlidingDrawer_allowSingleTap:I
-Landroid/R$styleable;->SlidingDrawer_animateOnClick:I
-Landroid/R$styleable;->SlidingDrawer_bottomOffset:I
-Landroid/R$styleable;->SlidingDrawer_content:I
-Landroid/R$styleable;->SlidingDrawer_handle:I
-Landroid/R$styleable;->SlidingDrawer_orientation:I
-Landroid/R$styleable;->SlidingDrawer_topOffset:I
-Landroid/R$styleable;->Switch:[I
-Landroid/R$styleable;->Switch_showText:I
-Landroid/R$styleable;->Switch_splitTrack:I
-Landroid/R$styleable;->Switch_switchMinWidth:I
-Landroid/R$styleable;->Switch_switchPadding:I
-Landroid/R$styleable;->Switch_switchTextAppearance:I
-Landroid/R$styleable;->Switch_textOff:I
-Landroid/R$styleable;->Switch_textOn:I
-Landroid/R$styleable;->Switch_thumb:I
-Landroid/R$styleable;->Switch_thumbTextPadding:I
-Landroid/R$styleable;->Switch_track:I
-Landroid/R$styleable;->TextAppearance:[I
-Landroid/R$styleable;->TextAppearance_textAllCaps:I
-Landroid/R$styleable;->TextAppearance_textColor:I
-Landroid/R$styleable;->TextAppearance_textColorHighlight:I
-Landroid/R$styleable;->TextAppearance_textColorHint:I
-Landroid/R$styleable;->TextAppearance_textColorLink:I
-Landroid/R$styleable;->TextAppearance_textSize:I
-Landroid/R$styleable;->TextAppearance_textStyle:I
-Landroid/R$styleable;->TextAppearance_typeface:I
-Landroid/R$styleable;->TextView:[I
-Landroid/R$styleable;->TextView_autoLink:I
-Landroid/R$styleable;->TextView_autoText:I
-Landroid/R$styleable;->TextView_bufferType:I
-Landroid/R$styleable;->TextView_capitalize:I
-Landroid/R$styleable;->TextView_cursorVisible:I
-Landroid/R$styleable;->TextView_digits:I
-Landroid/R$styleable;->TextView_drawableBottom:I
-Landroid/R$styleable;->TextView_drawableEnd:I
-Landroid/R$styleable;->TextView_drawableLeft:I
-Landroid/R$styleable;->TextView_drawablePadding:I
-Landroid/R$styleable;->TextView_drawableRight:I
-Landroid/R$styleable;->TextView_drawableStart:I
-Landroid/R$styleable;->TextView_drawableTop:I
-Landroid/R$styleable;->TextView_editable:I
-Landroid/R$styleable;->TextView_ellipsize:I
-Landroid/R$styleable;->TextView_ems:I
-Landroid/R$styleable;->TextView_enabled:I
-Landroid/R$styleable;->TextView_freezesText:I
-Landroid/R$styleable;->TextView_gravity:I
-Landroid/R$styleable;->TextView_height:I
-Landroid/R$styleable;->TextView_hint:I
-Landroid/R$styleable;->TextView_imeActionId:I
-Landroid/R$styleable;->TextView_imeActionLabel:I
-Landroid/R$styleable;->TextView_imeOptions:I
-Landroid/R$styleable;->TextView_includeFontPadding:I
-Landroid/R$styleable;->TextView_inputMethod:I
-Landroid/R$styleable;->TextView_inputType:I
-Landroid/R$styleable;->TextView_lines:I
-Landroid/R$styleable;->TextView_lineSpacingExtra:I
-Landroid/R$styleable;->TextView_lineSpacingMultiplier:I
-Landroid/R$styleable;->TextView_linksClickable:I
-Landroid/R$styleable;->TextView_marqueeRepeatLimit:I
-Landroid/R$styleable;->TextView_maxEms:I
-Landroid/R$styleable;->TextView_maxHeight:I
-Landroid/R$styleable;->TextView_maxLength:I
-Landroid/R$styleable;->TextView_maxLines:I
-Landroid/R$styleable;->TextView_maxWidth:I
-Landroid/R$styleable;->TextView_minEms:I
-Landroid/R$styleable;->TextView_minHeight:I
-Landroid/R$styleable;->TextView_minLines:I
-Landroid/R$styleable;->TextView_minWidth:I
-Landroid/R$styleable;->TextView_numeric:I
-Landroid/R$styleable;->TextView_password:I
-Landroid/R$styleable;->TextView_phoneNumber:I
-Landroid/R$styleable;->TextView_privateImeOptions:I
-Landroid/R$styleable;->TextView_scrollHorizontally:I
-Landroid/R$styleable;->TextView_selectAllOnFocus:I
-Landroid/R$styleable;->TextView_shadowColor:I
-Landroid/R$styleable;->TextView_shadowDx:I
-Landroid/R$styleable;->TextView_shadowDy:I
-Landroid/R$styleable;->TextView_shadowRadius:I
-Landroid/R$styleable;->TextView_singleLine:I
-Landroid/R$styleable;->TextView_text:I
-Landroid/R$styleable;->TextView_textAllCaps:I
-Landroid/R$styleable;->TextView_textAppearance:I
-Landroid/R$styleable;->TextView_textColor:I
-Landroid/R$styleable;->TextView_textColorHighlight:I
-Landroid/R$styleable;->TextView_textColorHint:I
-Landroid/R$styleable;->TextView_textColorLink:I
-Landroid/R$styleable;->TextView_textCursorDrawable:I
-Landroid/R$styleable;->TextView_textIsSelectable:I
-Landroid/R$styleable;->TextView_textScaleX:I
-Landroid/R$styleable;->TextView_textSelectHandle:I
-Landroid/R$styleable;->TextView_textSelectHandleLeft:I
-Landroid/R$styleable;->TextView_textSelectHandleRight:I
-Landroid/R$styleable;->TextView_textSize:I
-Landroid/R$styleable;->TextView_textStyle:I
-Landroid/R$styleable;->TextView_typeface:I
-Landroid/R$styleable;->TextView_width:I
-Landroid/R$styleable;->Theme:[I
-Landroid/R$styleable;->View:[I
-Landroid/R$styleable;->ViewDrawableStates:[I
-Landroid/R$styleable;->ViewGroup_Layout:[I
-Landroid/R$styleable;->ViewGroup_Layout_layout_height:I
-Landroid/R$styleable;->ViewGroup_Layout_layout_width:I
-Landroid/R$styleable;->ViewGroup_MarginLayout:[I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_height:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_margin:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginBottom:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginLeft:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginRight:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_marginTop:I
-Landroid/R$styleable;->ViewGroup_MarginLayout_layout_width:I
-Landroid/R$styleable;->View_alpha:I
-Landroid/R$styleable;->View_background:I
-Landroid/R$styleable;->View_clickable:I
-Landroid/R$styleable;->View_contentDescription:I
-Landroid/R$styleable;->View_drawingCacheQuality:I
-Landroid/R$styleable;->View_duplicateParentState:I
-Landroid/R$styleable;->View_fadingEdge:I
-Landroid/R$styleable;->View_filterTouchesWhenObscured:I
-Landroid/R$styleable;->View_fitsSystemWindows:I
-Landroid/R$styleable;->View_focusable:I
-Landroid/R$styleable;->View_focusableInTouchMode:I
-Landroid/R$styleable;->View_hapticFeedbackEnabled:I
-Landroid/R$styleable;->View_id:I
-Landroid/R$styleable;->View_isScrollContainer:I
-Landroid/R$styleable;->View_keepScreenOn:I
-Landroid/R$styleable;->View_longClickable:I
-Landroid/R$styleable;->View_minHeight:I
-Landroid/R$styleable;->View_minWidth:I
-Landroid/R$styleable;->View_nextFocusDown:I
-Landroid/R$styleable;->View_nextFocusLeft:I
-Landroid/R$styleable;->View_nextFocusRight:I
-Landroid/R$styleable;->View_nextFocusUp:I
-Landroid/R$styleable;->View_onClick:I
-Landroid/R$styleable;->View_overScrollMode:I
-Landroid/R$styleable;->View_padding:I
-Landroid/R$styleable;->View_paddingBottom:I
-Landroid/R$styleable;->View_paddingEnd:I
-Landroid/R$styleable;->View_paddingLeft:I
-Landroid/R$styleable;->View_paddingRight:I
-Landroid/R$styleable;->View_paddingStart:I
-Landroid/R$styleable;->View_paddingTop:I
-Landroid/R$styleable;->View_rotation:I
-Landroid/R$styleable;->View_rotationX:I
-Landroid/R$styleable;->View_rotationY:I
-Landroid/R$styleable;->View_saveEnabled:I
-Landroid/R$styleable;->View_scaleX:I
-Landroid/R$styleable;->View_scaleY:I
-Landroid/R$styleable;->View_scrollbarDefaultDelayBeforeFade:I
-Landroid/R$styleable;->View_scrollbarFadeDuration:I
-Landroid/R$styleable;->View_scrollbars:I
-Landroid/R$styleable;->View_scrollbarSize:I
-Landroid/R$styleable;->View_scrollbarStyle:I
-Landroid/R$styleable;->View_scrollbarThumbHorizontal:I
-Landroid/R$styleable;->View_scrollbarThumbVertical:I
-Landroid/R$styleable;->View_scrollbarTrackHorizontal:I
-Landroid/R$styleable;->View_scrollbarTrackVertical:I
-Landroid/R$styleable;->View_scrollX:I
-Landroid/R$styleable;->View_scrollY:I
-Landroid/R$styleable;->View_soundEffectsEnabled:I
-Landroid/R$styleable;->View_tag:I
-Landroid/R$styleable;->View_transformPivotX:I
-Landroid/R$styleable;->View_transformPivotY:I
-Landroid/R$styleable;->View_translationX:I
-Landroid/R$styleable;->View_translationY:I
-Landroid/R$styleable;->View_visibility:I
-Landroid/R$styleable;->Window:[I
-Landroid/R$styleable;->Window_windowBackground:I
-Landroid/R$styleable;->Window_windowFrame:I
 Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
 Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
 Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
@@ -589,446 +325,6 @@
 Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
 Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
 Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
-Lcom/android/internal/R$anim;->fade_in:I
-Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
-Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
-Lcom/android/internal/R$array;->config_mobile_hotspot_provision_app:I
-Lcom/android/internal/R$array;->config_sms_enabled_locking_shift_tables:I
-Lcom/android/internal/R$array;->config_sms_enabled_single_shift_tables:I
-Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I
-Lcom/android/internal/R$array;->config_tether_upstream_types:I
-Lcom/android/internal/R$array;->config_tether_usb_regexs:I
-Lcom/android/internal/R$array;->config_tether_wifi_regexs:I
-Lcom/android/internal/R$array;->maps_starting_lat_lng:I
-Lcom/android/internal/R$array;->maps_starting_zoom:I
-Lcom/android/internal/R$attr;->actionBarStyle:I
-Lcom/android/internal/R$attr;->buttonStyle:I
-Lcom/android/internal/R$attr;->description:I
-Lcom/android/internal/R$attr;->editTextStyle:I
-Lcom/android/internal/R$attr;->mapViewStyle:I
-Lcom/android/internal/R$attr;->popupWindowStyle:I
-Lcom/android/internal/R$attr;->state_above_anchor:I
-Lcom/android/internal/R$attr;->state_focused:I
-Lcom/android/internal/R$attr;->state_pressed:I
-Lcom/android/internal/R$attr;->state_selected:I
-Lcom/android/internal/R$attr;->switchStyle:I
-Lcom/android/internal/R$attr;->text:I
-Lcom/android/internal/R$attr;->title:I
-Lcom/android/internal/R$attr;->webViewStyle:I
-Lcom/android/internal/R$bool;-><init>()V
-Lcom/android/internal/R$bool;->config_automatic_brightness_available:I
-Lcom/android/internal/R$bool;->config_intrusiveNotificationLed:I
-Lcom/android/internal/R$bool;->config_mms_content_disposition_support:I
-Lcom/android/internal/R$bool;->config_showNavigationBar:I
-Lcom/android/internal/R$dimen;-><init>()V
-Lcom/android/internal/R$dimen;->item_touch_helper_max_drag_scroll_per_frame:I
-Lcom/android/internal/R$dimen;->navigation_bar_height:I
-Lcom/android/internal/R$dimen;->navigation_bar_height_landscape:I
-Lcom/android/internal/R$dimen;->navigation_bar_width:I
-Lcom/android/internal/R$dimen;->status_bar_height:I
-Lcom/android/internal/R$dimen;->toast_y_offset:I
-Lcom/android/internal/R$drawable;->btn_check_off:I
-Lcom/android/internal/R$drawable;->compass_arrow:I
-Lcom/android/internal/R$drawable;->compass_base:I
-Lcom/android/internal/R$drawable;->ic_maps_indicator_current_position_anim:I
-Lcom/android/internal/R$drawable;->ic_menu_close_clear_cancel:I
-Lcom/android/internal/R$drawable;->loading_tile_android:I
-Lcom/android/internal/R$drawable;->maps_google_logo:I
-Lcom/android/internal/R$drawable;->no_tile_256:I
-Lcom/android/internal/R$drawable;->reticle:I
-Lcom/android/internal/R$drawable;->stat_sys_download:I
-Lcom/android/internal/R$fraction;->config_autoBrightnessAdjustmentMaxGamma:I
-Lcom/android/internal/R$id;->account_name:I
-Lcom/android/internal/R$id;->account_type:I
-Lcom/android/internal/R$id;->alertTitle:I
-Lcom/android/internal/R$id;->allow_button:I
-Lcom/android/internal/R$id;->amPm:I
-Lcom/android/internal/R$id;->authtoken_type:I
-Lcom/android/internal/R$id;->background:I
-Lcom/android/internal/R$id;->back_button:I
-Lcom/android/internal/R$id;->body:I
-Lcom/android/internal/R$id;->buttonPanel:I
-Lcom/android/internal/R$id;->camera:I
-Lcom/android/internal/R$id;->cancel:I
-Lcom/android/internal/R$id;->clip_children_set_tag:I
-Lcom/android/internal/R$id;->clip_children_tag:I
-Lcom/android/internal/R$id;->clip_to_padding_tag:I
-Lcom/android/internal/R$id;->closeButton:I
-Lcom/android/internal/R$id;->content:I
-Lcom/android/internal/R$id;->contentPanel:I
-Lcom/android/internal/R$id;->custom:I
-Lcom/android/internal/R$id;->customPanel:I
-Lcom/android/internal/R$id;->datePicker:I
-Lcom/android/internal/R$id;->day:I
-Lcom/android/internal/R$id;->deny_button:I
-Lcom/android/internal/R$id;->description:I
-Lcom/android/internal/R$id;->edit:I
-Lcom/android/internal/R$id;->edittext_container:I
-Lcom/android/internal/R$id;->find_next:I
-Lcom/android/internal/R$id;->find_prev:I
-Lcom/android/internal/R$id;->icon:I
-Lcom/android/internal/R$id;->keyboard:I
-Lcom/android/internal/R$id;->keyboardView:I
-Lcom/android/internal/R$id;->line1:I
-Lcom/android/internal/R$id;->list_item:I
-Lcom/android/internal/R$id;->matches:I
-Lcom/android/internal/R$id;->mediacontroller_progress:I
-Lcom/android/internal/R$id;->media_actions:I
-Lcom/android/internal/R$id;->message:I
-Lcom/android/internal/R$id;->minute:I
-Lcom/android/internal/R$id;->month:I
-Lcom/android/internal/R$id;->name:I
-Lcom/android/internal/R$id;->notification_header:I
-Lcom/android/internal/R$id;->ok:I
-Lcom/android/internal/R$id;->overlay:I
-Lcom/android/internal/R$id;->packages_list:I
-Lcom/android/internal/R$id;->package_label:I
-Lcom/android/internal/R$id;->parentPanel:I
-Lcom/android/internal/R$id;->pause:I
-Lcom/android/internal/R$id;->pending_intent_tag:I
-Lcom/android/internal/R$id;->progress:I
-Lcom/android/internal/R$id;->redo:I
-Lcom/android/internal/R$id;->remote_input_tag:I
-Lcom/android/internal/R$id;->right_icon:I
-Lcom/android/internal/R$id;->search_src_text:I
-Lcom/android/internal/R$id;->share:I
-Lcom/android/internal/R$id;->shortcut:I
-Lcom/android/internal/R$id;->status_bar_latest_event_content:I
-Lcom/android/internal/R$id;->tabcontent:I
-Lcom/android/internal/R$id;->tabs:I
-Lcom/android/internal/R$id;->text1:I
-Lcom/android/internal/R$id;->text2:I
-Lcom/android/internal/R$id;->text:I
-Lcom/android/internal/R$id;->time:I
-Lcom/android/internal/R$id;->timePicker:I
-Lcom/android/internal/R$id;->time_current:I
-Lcom/android/internal/R$id;->title:I
-Lcom/android/internal/R$id;->titleDivider:I
-Lcom/android/internal/R$id;->titleDividerTop:I
-Lcom/android/internal/R$id;->title_container:I
-Lcom/android/internal/R$id;->title_template:I
-Lcom/android/internal/R$id;->topPanel:I
-Lcom/android/internal/R$id;->up:I
-Lcom/android/internal/R$id;->year:I
-Lcom/android/internal/R$id;->zoomControls:I
-Lcom/android/internal/R$id;->zoomMagnify:I
-Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
-Lcom/android/internal/R$integer;->config_screenBrightnessSettingMaximum:I
-Lcom/android/internal/R$integer;->config_screenBrightnessSettingMinimum:I
-Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
-Lcom/android/internal/R$interpolator;->accelerate_cubic:I
-Lcom/android/internal/R$interpolator;->decelerate_cubic:I
-Lcom/android/internal/R$layout;->notification_template_material_base:I
-Lcom/android/internal/R$layout;->preference_header_item:I
-Lcom/android/internal/R$layout;->screen_title:I
-Lcom/android/internal/R$layout;->select_dialog:I
-Lcom/android/internal/R$layout;->select_dialog_multichoice:I
-Lcom/android/internal/R$layout;->select_dialog_singlechoice:I
-Lcom/android/internal/R$layout;->webview_find:I
-Lcom/android/internal/R$layout;->zoom_magnify:I
-Lcom/android/internal/R$plurals;->matches_found:I
-Lcom/android/internal/R$raw;->loaderror:I
-Lcom/android/internal/R$raw;->nodomain:I
-Lcom/android/internal/R$string;->byteShort:I
-Lcom/android/internal/R$string;->cancel:I
-Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I
-Lcom/android/internal/R$string;->gigabyteShort:I
-Lcom/android/internal/R$string;->kilobyteShort:I
-Lcom/android/internal/R$string;->map:I
-Lcom/android/internal/R$string;->megabyteShort:I
-Lcom/android/internal/R$string;->notification_title:I
-Lcom/android/internal/R$string;->no_matches:I
-Lcom/android/internal/R$string;->ok:I
-Lcom/android/internal/R$string;->petabyteShort:I
-Lcom/android/internal/R$string;->redo:I
-Lcom/android/internal/R$string;->share:I
-Lcom/android/internal/R$string;->terabyteShort:I
-Lcom/android/internal/R$string;->whichApplication:I
-Lcom/android/internal/R$style;->Animation_DropDownDown:I
-Lcom/android/internal/R$style;->Animation_DropDownUp:I
-Lcom/android/internal/R$style;->Animation_PopupWindow:I
-Lcom/android/internal/R$style;->Theme:I
-Lcom/android/internal/R$style;->Theme_Dialog_Alert:I
-Lcom/android/internal/R$style;->Theme_Holo_Light:I
-Lcom/android/internal/R$style;->Theme_Light:I
-Lcom/android/internal/R$styleable;-><init>()V
-Lcom/android/internal/R$styleable;->AbsListView:[I
-Lcom/android/internal/R$styleable;->AbsListView_cacheColorHint:I
-Lcom/android/internal/R$styleable;->AbsListView_choiceMode:I
-Lcom/android/internal/R$styleable;->AbsListView_drawSelectorOnTop:I
-Lcom/android/internal/R$styleable;->AbsListView_fastScrollAlwaysVisible:I
-Lcom/android/internal/R$styleable;->AbsListView_fastScrollEnabled:I
-Lcom/android/internal/R$styleable;->AbsListView_listSelector:I
-Lcom/android/internal/R$styleable;->AbsListView_scrollingCache:I
-Lcom/android/internal/R$styleable;->AbsListView_smoothScrollbar:I
-Lcom/android/internal/R$styleable;->AbsListView_stackFromBottom:I
-Lcom/android/internal/R$styleable;->AbsListView_textFilterEnabled:I
-Lcom/android/internal/R$styleable;->AbsListView_transcriptMode:I
-Lcom/android/internal/R$styleable;->AbsSpinner:[I
-Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
-Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
-Lcom/android/internal/R$styleable;->ActionMode:[I
-Lcom/android/internal/R$styleable;->AdapterViewAnimator:[I
-Lcom/android/internal/R$styleable;->AdapterViewFlipper:[I
-Lcom/android/internal/R$styleable;->AlertDialog:[I
-Lcom/android/internal/R$styleable;->AnalogClock:[I
-Lcom/android/internal/R$styleable;->AndroidManifest:[I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_excludeFromRecents:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_exported:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_hardwareAccelerated:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_icon:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_immersive:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_label:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_launchMode:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_logo:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_noHistory:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_screenOrientation:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_taskAffinity:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_theme:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_uiOptions:I
-Lcom/android/internal/R$styleable;->AndroidManifestActivity_windowSoftInputMode:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_label:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_largeHeap:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
-Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
-Lcom/android/internal/R$styleable;->AndroidManifestData:[I
-Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
-Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
-Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
-Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I
-Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I
-Lcom/android/internal/R$styleable;->AndroidManifestService:[I
-Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
-Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_minSdkVersion:I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesSdk_targetSdkVersion:I
-Lcom/android/internal/R$styleable;->AndroidManifest_installLocation:I
-Lcom/android/internal/R$styleable;->AndroidManifest_sharedUserId:I
-Lcom/android/internal/R$styleable;->AndroidManifest_versionCode:I
-Lcom/android/internal/R$styleable;->AndroidManifest_versionName:I
-Lcom/android/internal/R$styleable;->AutoCompleteTextView:[I
-Lcom/android/internal/R$styleable;->CheckBoxPreference:[I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_disableDependentsState:I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I
-Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
-Lcom/android/internal/R$styleable;->CheckedTextView:[I
-Lcom/android/internal/R$styleable;->CheckedTextView_checked:I
-Lcom/android/internal/R$styleable;->CheckedTextView_checkMark:I
-Lcom/android/internal/R$styleable;->CompoundButton:[I
-Lcom/android/internal/R$styleable;->CompoundButton_button:I
-Lcom/android/internal/R$styleable;->CompoundButton_checked:I
-Lcom/android/internal/R$styleable;->ContactsDataKind:[I
-Lcom/android/internal/R$styleable;->DatePicker:[I
-Lcom/android/internal/R$styleable;->DialogPreference:[I
-Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
-Lcom/android/internal/R$styleable;->Dream:[I
-Lcom/android/internal/R$styleable;->EdgeEffect:[I
-Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
-Lcom/android/internal/R$styleable;->FastScroll:[I
-Lcom/android/internal/R$styleable;->FrameLayout:[I
-Lcom/android/internal/R$styleable;->FrameLayout_Layout:[I
-Lcom/android/internal/R$styleable;->Gallery:[I
-Lcom/android/internal/R$styleable;->GridView:[I
-Lcom/android/internal/R$styleable;->IconMenuView:[I
-Lcom/android/internal/R$styleable;->ImageView:[I
-Lcom/android/internal/R$styleable;->ImageView_scaleType:I
-Lcom/android/internal/R$styleable;->ImageView_src:I
-Lcom/android/internal/R$styleable;->Keyboard:[I
-Lcom/android/internal/R$styleable;->KeyboardView:[I
-Lcom/android/internal/R$styleable;->Keyboard_Key:[I
-Lcom/android/internal/R$styleable;->Keyboard_Row:[I
-Lcom/android/internal/R$styleable;->ListPreference:[I
-Lcom/android/internal/R$styleable;->ListPreference_entries:I
-Lcom/android/internal/R$styleable;->ListView:[I
-Lcom/android/internal/R$styleable;->ListView_divider:I
-Lcom/android/internal/R$styleable;->ListView_dividerHeight:I
-Lcom/android/internal/R$styleable;->ListView_entries:I
-Lcom/android/internal/R$styleable;->ListView_footerDividersEnabled:I
-Lcom/android/internal/R$styleable;->ListView_headerDividersEnabled:I
-Lcom/android/internal/R$styleable;->ListView_overScrollFooter:I
-Lcom/android/internal/R$styleable;->ListView_overScrollHeader:I
-Lcom/android/internal/R$styleable;->MapView:[I
-Lcom/android/internal/R$styleable;->MapView_apiKey:I
-Lcom/android/internal/R$styleable;->MenuGroup:[I
-Lcom/android/internal/R$styleable;->MenuItem:[I
-Lcom/android/internal/R$styleable;->NumberPicker:[I
-Lcom/android/internal/R$styleable;->PopupWindow:[I
-Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
-Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I
-Lcom/android/internal/R$styleable;->Preference:[I
-Lcom/android/internal/R$styleable;->PreferenceGroup:[I
-Lcom/android/internal/R$styleable;->PreferenceGroup_orderingFromXml:I
-Lcom/android/internal/R$styleable;->Preference_defaultValue:I
-Lcom/android/internal/R$styleable;->Preference_dependency:I
-Lcom/android/internal/R$styleable;->Preference_enabled:I
-Lcom/android/internal/R$styleable;->Preference_fragment:I
-Lcom/android/internal/R$styleable;->Preference_icon:I
-Lcom/android/internal/R$styleable;->Preference_key:I
-Lcom/android/internal/R$styleable;->Preference_layout:I
-Lcom/android/internal/R$styleable;->Preference_order:I
-Lcom/android/internal/R$styleable;->Preference_persistent:I
-Lcom/android/internal/R$styleable;->Preference_selectable:I
-Lcom/android/internal/R$styleable;->Preference_shouldDisableView:I
-Lcom/android/internal/R$styleable;->Preference_summary:I
-Lcom/android/internal/R$styleable;->Preference_title:I
-Lcom/android/internal/R$styleable;->Preference_widgetLayout:I
-Lcom/android/internal/R$styleable;->ProgressBar:[I
-Lcom/android/internal/R$styleable;->QuickContactBadge:[I
-Lcom/android/internal/R$styleable;->RingtonePreference:[I
-Lcom/android/internal/R$styleable;->ScrollView:[I
-Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
-Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I
-Lcom/android/internal/R$styleable;->Switch:[I
-Lcom/android/internal/R$styleable;->SwitchPreference:[I
-Lcom/android/internal/R$styleable;->SyncAdapter:[I
-Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
-Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
-Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
-Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
-Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
-Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
-Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
-Lcom/android/internal/R$styleable;->TabWidget:[I
-Lcom/android/internal/R$styleable;->TextAppearance:[I
-Lcom/android/internal/R$styleable;->TextAppearance_fontFamily:I
-Lcom/android/internal/R$styleable;->TextAppearance_textAllCaps:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColor:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorHighlight:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorHint:I
-Lcom/android/internal/R$styleable;->TextAppearance_textColorLink:I
-Lcom/android/internal/R$styleable;->TextAppearance_textSize:I
-Lcom/android/internal/R$styleable;->TextAppearance_textStyle:I
-Lcom/android/internal/R$styleable;->TextAppearance_typeface:I
-Lcom/android/internal/R$styleable;->TextClock:[I
-Lcom/android/internal/R$styleable;->TextView:[I
-Lcom/android/internal/R$styleable;->TextViewAppearance:[I
-Lcom/android/internal/R$styleable;->TextViewAppearance_textAppearance:I
-Lcom/android/internal/R$styleable;->TextView_autoLink:I
-Lcom/android/internal/R$styleable;->TextView_autoText:I
-Lcom/android/internal/R$styleable;->TextView_bufferType:I
-Lcom/android/internal/R$styleable;->TextView_capitalize:I
-Lcom/android/internal/R$styleable;->TextView_cursorVisible:I
-Lcom/android/internal/R$styleable;->TextView_digits:I
-Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
-Lcom/android/internal/R$styleable;->TextView_drawableEnd:I
-Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
-Lcom/android/internal/R$styleable;->TextView_drawablePadding:I
-Lcom/android/internal/R$styleable;->TextView_drawableRight:I
-Lcom/android/internal/R$styleable;->TextView_drawableStart:I
-Lcom/android/internal/R$styleable;->TextView_drawableTop:I
-Lcom/android/internal/R$styleable;->TextView_editable:I
-Lcom/android/internal/R$styleable;->TextView_editorExtras:I
-Lcom/android/internal/R$styleable;->TextView_ellipsize:I
-Lcom/android/internal/R$styleable;->TextView_ems:I
-Lcom/android/internal/R$styleable;->TextView_enabled:I
-Lcom/android/internal/R$styleable;->TextView_freezesText:I
-Lcom/android/internal/R$styleable;->TextView_gravity:I
-Lcom/android/internal/R$styleable;->TextView_height:I
-Lcom/android/internal/R$styleable;->TextView_hint:I
-Lcom/android/internal/R$styleable;->TextView_imeActionId:I
-Lcom/android/internal/R$styleable;->TextView_imeActionLabel:I
-Lcom/android/internal/R$styleable;->TextView_imeOptions:I
-Lcom/android/internal/R$styleable;->TextView_includeFontPadding:I
-Lcom/android/internal/R$styleable;->TextView_inputMethod:I
-Lcom/android/internal/R$styleable;->TextView_inputType:I
-Lcom/android/internal/R$styleable;->TextView_lines:I
-Lcom/android/internal/R$styleable;->TextView_lineSpacingExtra:I
-Lcom/android/internal/R$styleable;->TextView_lineSpacingMultiplier:I
-Lcom/android/internal/R$styleable;->TextView_linksClickable:I
-Lcom/android/internal/R$styleable;->TextView_marqueeRepeatLimit:I
-Lcom/android/internal/R$styleable;->TextView_maxEms:I
-Lcom/android/internal/R$styleable;->TextView_maxHeight:I
-Lcom/android/internal/R$styleable;->TextView_maxLength:I
-Lcom/android/internal/R$styleable;->TextView_maxLines:I
-Lcom/android/internal/R$styleable;->TextView_maxWidth:I
-Lcom/android/internal/R$styleable;->TextView_minEms:I
-Lcom/android/internal/R$styleable;->TextView_minHeight:I
-Lcom/android/internal/R$styleable;->TextView_minLines:I
-Lcom/android/internal/R$styleable;->TextView_minWidth:I
-Lcom/android/internal/R$styleable;->TextView_numeric:I
-Lcom/android/internal/R$styleable;->TextView_password:I
-Lcom/android/internal/R$styleable;->TextView_phoneNumber:I
-Lcom/android/internal/R$styleable;->TextView_privateImeOptions:I
-Lcom/android/internal/R$styleable;->TextView_scrollHorizontally:I
-Lcom/android/internal/R$styleable;->TextView_selectAllOnFocus:I
-Lcom/android/internal/R$styleable;->TextView_shadowColor:I
-Lcom/android/internal/R$styleable;->TextView_shadowDx:I
-Lcom/android/internal/R$styleable;->TextView_shadowDy:I
-Lcom/android/internal/R$styleable;->TextView_shadowRadius:I
-Lcom/android/internal/R$styleable;->TextView_singleLine:I
-Lcom/android/internal/R$styleable;->TextView_text:I
-Lcom/android/internal/R$styleable;->TextView_textAllCaps:I
-Lcom/android/internal/R$styleable;->TextView_textAppearance:I
-Lcom/android/internal/R$styleable;->TextView_textColor:I
-Lcom/android/internal/R$styleable;->TextView_textColorHighlight:I
-Lcom/android/internal/R$styleable;->TextView_textColorHint:I
-Lcom/android/internal/R$styleable;->TextView_textColorLink:I
-Lcom/android/internal/R$styleable;->TextView_textCursorDrawable:I
-Lcom/android/internal/R$styleable;->TextView_textEditSuggestionItemLayout:I
-Lcom/android/internal/R$styleable;->TextView_textIsSelectable:I
-Lcom/android/internal/R$styleable;->TextView_textScaleX:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandle:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandleLeft:I
-Lcom/android/internal/R$styleable;->TextView_textSelectHandleRight:I
-Lcom/android/internal/R$styleable;->TextView_textSize:I
-Lcom/android/internal/R$styleable;->TextView_textStyle:I
-Lcom/android/internal/R$styleable;->TextView_typeface:I
-Lcom/android/internal/R$styleable;->TextView_width:I
-Lcom/android/internal/R$styleable;->Theme:[I
-Lcom/android/internal/R$styleable;->TwoLineListItem:[I
-Lcom/android/internal/R$styleable;->View:[I
-Lcom/android/internal/R$styleable;->ViewAnimator:[I
-Lcom/android/internal/R$styleable;->ViewFlipper:[I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout:[I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_height:I
-Lcom/android/internal/R$styleable;->ViewGroup_Layout_layout_width:I
-Lcom/android/internal/R$styleable;->ViewStub:[I
-Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
-Lcom/android/internal/R$styleable;->ViewStub_layout:I
-Lcom/android/internal/R$styleable;->View_background:I
-Lcom/android/internal/R$styleable;->View_clickable:I
-Lcom/android/internal/R$styleable;->View_focusable:I
-Lcom/android/internal/R$styleable;->View_id:I
-Lcom/android/internal/R$styleable;->View_longClickable:I
-Lcom/android/internal/R$styleable;->WallpaperPreviewInfo:[I
-Lcom/android/internal/R$styleable;->Window:[I
-Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
-Lcom/android/internal/R$styleable;->Window_windowBackground:I
-Lcom/android/internal/R$styleable;->Window_windowFullscreen:I
-Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
-Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
-Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
-Lcom/android/internal/R$xml;->power_profile:I
 Lcom/android/internal/statusbar/IStatusBar$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBar;
 Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V
 Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService;
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 25cd342..6470a04 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -103,8 +103,6 @@
  * When writing an activity to satisfy these requests one must pass in the AccountManagerResponse
  * and return the result via that response when the activity finishes (or whenever else  the
  * activity author deems it is the correct time to respond).
- * The {@link AccountAuthenticatorActivity} handles this, so one may wish to extend that when
- * writing activities to handle these requests.
  */
 public abstract class AbstractAccountAuthenticator {
     private static final String TAG = "AccountAuthenticator";
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
index 967aa04..65ba35f 100644
--- a/core/java/android/accounts/AccountAuthenticatorActivity.java
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -32,7 +32,11 @@
  * This result will be sent as the result of the request when the activity finishes. If this
  * is never set or if it is set to null then error {@link AccountManager#ERROR_CODE_CANCELED}
  * will be called on the response.
+ *
+ * @deprecated Applications should extend Activity themselves. This class is not compatible with
+ *   AppCompat, and the functionality it provides is not complex.
  */
+@Deprecated
 public class AccountAuthenticatorActivity extends Activity {
     private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
     private Bundle mResultBundle = null;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9902f6a..794ffcb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2224,6 +2224,15 @@
     }
 
     @Override
+    public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+        try {
+            return createPackageContextAsUser(getPackageName(), flags, user);
+        } catch (NameNotFoundException e) {
+            throw new IllegalStateException("Own package not found: package=" + getPackageName());
+        }
+    }
+
+    @Override
     public Context createContextForSplit(String splitName) throws NameNotFoundException {
         if (!mPackageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
             // All Splits are always loaded.
diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java
index e08f25a..22de878 100644
--- a/core/java/android/app/ExpandableListActivity.java
+++ b/core/java/android/app/ExpandableListActivity.java
@@ -150,7 +150,11 @@
  * 
  * @see #setListAdapter
  * @see android.widget.ExpandableListView
+ *
+ * @deprecated Use {@link androidx.recyclerview.widget.RecyclerView} or use
+ *   {@link android.widget.ExpandableListView} directly
  */
+@Deprecated
 public class ExpandableListActivity extends Activity implements
         OnCreateContextMenuListener,
         ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index f2c9f61..a3e0845 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -25,7 +25,7 @@
      * Enables the car mode. Only the system can do this.
      * @hide
      */
-    void enableCarMode(int flags);
+    void enableCarMode(int flags, int priority, String callingPackage);
 
     /**
      * Disables the car mode.
@@ -34,6 +34,12 @@
     void disableCarMode(int flags);
 
     /**
+     * Disables car mode (the original version is marked unsupported app usage so cannot be changed
+     * for the time being).
+     */
+    void disableCarModeByCallingPackage(int flags, String callingPackage);
+
+    /**
      * Return the current running mode.
      */
     int getCurrentModeType();
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 88e2356..b495b3c 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -53,7 +53,11 @@
  * Displays a list of all activities which can be performed
  * for a given intent. Launches when clicked.
  *
+ * @deprecated Applications can implement this UI themselves using
+ *   {@link androidx.recyclerview.widget.RecyclerView} and
+ *   {@link android.content.pm.PackageManager#queryIntentActivities(Intent, int)}
  */
+@Deprecated
 public abstract class LauncherActivity extends ListActivity {
     Intent mIntent;
     PackageManager mPackageManager;
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 2162521..810cca2 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -171,7 +171,11 @@
  *
  * @see #setListAdapter
  * @see android.widget.ListView
+ *
+ * @deprecated Use {@link androidx.fragment.app.ListFragment} or
+ *   {@link androidx.recyclerview.widget.RecyclerView} to implement your Activity instead.
  */
+@Deprecated
 public class ListActivity extends Activity {
     /**
      * This field should be made private, so it is hidden from the SDK.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ceadd85..47f0cf8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -628,6 +628,13 @@
      */
     public static final int FLAG_BUBBLE = 0x00001000;
 
+    /** @hide */
+    @IntDef({FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT, FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE,
+            FLAG_AUTO_CANCEL, FLAG_NO_CLEAR, FLAG_FOREGROUND_SERVICE, FLAG_HIGH_PRIORITY,
+            FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NotificationFlags{};
+
     public int flags;
 
     /** @hide */
@@ -4537,10 +4544,15 @@
         }
 
         /**
-         * @hide
+         * Set the value for a notification flag
+         *
+         * @param mask Bit mask of the flag
+         * @param value Status (on/off) of the flag
+         *
+         * @return The same Builder.
          */
         @NonNull
-        public Builder setFlag(int mask, boolean value) {
+        public Builder setFlag(@NotificationFlags int mask, boolean value) {
             if (value) {
                 mN.flags |= mask;
             } else {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 587d7b1..29cb3c1 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -653,7 +653,7 @@
                 new CachedServiceFetcher<UiModeManager>() {
             @Override
             public UiModeManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                return new UiModeManager();
+                return new UiModeManager(ctx.getOuterContext());
             }});
 
         registerService(Context.USB_SERVICE, UsbManager.class,
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 46316e1..8324787 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -17,6 +17,10 @@
 package android.app;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -68,6 +72,25 @@
      * of the broadcast to {@link Activity#RESULT_CANCELED}.
      */
     public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE";
+
+    /**
+     * Broadcast sent when the device's UI has switched to car mode, either by being placed in a car
+     * dock or explicit action of the user.
+     * <p>
+     * In addition to the behavior for {@link #ACTION_ENTER_CAR_MODE}, this broadcast includes the
+     * package name of the app which requested to enter car mode in the
+     * {@link #EXTRA_CALLING_PACKAGE}.  If an app requested to enter car mode using
+     * {@link #enableCarMode(int, int)} and specified a priority this will be specified in the
+     * {@link #EXTRA_PRIORITY}.
+     *
+     * This is primarily intended to be received by other components of the Android OS.
+     * <p>
+     * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES}
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED =
+            "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
     
     /**
      * Broadcast sent when the device's UI has switch away from car mode back
@@ -75,6 +98,28 @@
      * when the user exits car mode.
      */
     public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE";
+
+    /**
+     * Broadcast sent when the device's UI has switched away from car mode back to normal mode.
+     * Typically used by a car mode app, to dismiss itself when the user exits car mode.
+     * <p>
+     * In addition to the behavior for {@link #ACTION_EXIT_CAR_MODE}, this broadcast includes the
+     * package name of the app which requested to exit car mode in {@link #EXTRA_CALLING_PACKAGE}.
+     * If an app requested to enter car mode using {@link #enableCarMode(int, int)} and specified a
+     * priority this will be specified in the {@link #EXTRA_PRIORITY} when exiting car mode.
+     * <p>
+     * If {@link #DISABLE_CAR_MODE_ALL_PRIORITIES} is used when disabling car mode (i.e. this is
+     * initiated by the user via the persistent car mode notification), this broadcast is sent once
+     * for each priority level for which car mode is being disabled.
+     * <p>
+     * This is primarily intended to be received by other components of the Android OS.
+     * <p>
+     * Receiver requires permission: {@link android.Manifest.permission.HANDLE_CAR_MODE_CHANGES}
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED =
+            "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
     
     /**
      * Broadcast sent when the device's UI has switched to desk mode,
@@ -97,6 +142,24 @@
      */
     public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
 
+    /**
+     * String extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and
+     * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the package name of the app which
+     * requested to enter or exit car mode.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
+
+    /**
+     * Integer extra used with {@link #ACTION_ENTER_CAR_MODE_PRIORITIZED} and
+     * {@link #ACTION_EXIT_CAR_MODE_PRIORITIZED} to indicate the priority level at which car mode
+     * is being disabled.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
+
     /** @hide */
     @IntDef(prefix = { "MODE_" }, value = {
             MODE_NIGHT_AUTO,
@@ -126,10 +189,21 @@
 
     private IUiModeManager mService;
 
+    /**
+     * Context required for getting the opPackageName of API caller; maybe be {@code null} if the
+     * old constructor marked with UnSupportedAppUsage is used.
+     */
+    private @Nullable Context mContext;
+
     @UnsupportedAppUsage
     /*package*/ UiModeManager() throws ServiceNotFoundException {
+        this(null /* context */);
+    }
+
+    /*package*/ UiModeManager(Context context) throws ServiceNotFoundException {
         mService = IUiModeManager.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE));
+        mContext = context;
     }
 
     /**
@@ -152,6 +226,14 @@
      */
     public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 0x0002;
 
+    /** @hide */
+    @IntDef(prefix = { "ENABLE_CAR_MODE_" }, value = {
+            ENABLE_CAR_MODE_GO_CAR_HOME,
+            ENABLE_CAR_MODE_ALLOW_SLEEP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EnableCarMode {}
+
     /**
      * Force device into car mode, like it had been placed in the car dock.
      * This will cause the device to switch to the car home UI as part of
@@ -159,9 +241,54 @@
      * @param flags Must be 0.
      */
     public void enableCarMode(int flags) {
+        enableCarMode(DEFAULT_PRIORITY, flags);
+    }
+
+    /**
+     * Force device into car mode, like it had been placed in the car dock.  This will cause the
+     * device to switch to the car home UI as part of the mode switch.
+     * <p>
+     * An app may request to enter car mode when the system is already in car mode.  The app may
+     * specify a "priority" when entering car mode.  The device will remain in car mode
+     * (i.e. {@link #getCurrentModeType()} is {@link Configuration#UI_MODE_TYPE_CAR}) as long as
+     * there is a priority level at which car mode have been enabled.  For example assume app A
+     * enters car mode at priority level 100, and then app B enters car mode at the default priority
+     * (0).  If app A exits car mode, the device will remain in car mode until app B exits car mode.
+     * <p>
+     * Specifying a priority level when entering car mode is important in cases where multiple apps
+     * on a device implement a car-mode {@link android.telecom.InCallService} (see
+     * {@link android.telecom.TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}).  The
+     * {@link android.telecom.InCallService} associated with the highest priority app which entered
+     * car mode will be bound to by Telecom and provided with information about ongoing calls on
+     * the device.
+     * <p>
+     * System apps holding the required permission can enable car mode when the app determines the
+     * correct conditions exist for that app to be in car mode.  The device maker should ensure that
+     * where multiple apps exist on the device which can potentially enter car mode, appropriate
+     * priorities are used to ensure that calls delivered by the
+     * {@link android.telecom.InCallService} API are delivered to the highest priority app.
+     * If app A and app B can both potentially enable car mode, and it is desired that app B is the
+     * one which should receive call information, the priority for app B should be higher than the
+     * one for app A.
+     * <p>
+     * When an app uses a priority to enable car mode, they can disable car mode at the specified
+     * priority level using {@link #disableCarMode(int)}.  An app may only enable car mode at a
+     * single priority.
+     * <p>
+     * Public apps are assumed to enter/exit car mode at {@link #DEFAULT_PRIORITY}.
+     *
+     * @param priority The declared priority for the caller.
+     * @param flags Car mode flags.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
+    public void enableCarMode(@IntRange(from = 0) int priority, @EnableCarMode int flags) {
         if (mService != null) {
             try {
-                mService.enableCarMode(flags);
+                mService.enableCarMode(flags, priority,
+                        mContext == null ? null : mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -176,15 +303,44 @@
      * being in car mode).
      */
     public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001;
+
+    /**
+     * Flag for use with {@link #disableCarMode(int)}: Disables car mode at ALL priority levels.
+     * Primarily intended for use from {@link com.android.internal.app.DisableCarModeActivity} to
+     * provide the user with a means to exit car mode at all priority levels.
+     * @hide
+     */
+    public static final int DISABLE_CAR_MODE_ALL_PRIORITIES = 0x0002;
+
+    /** @hide */
+    @IntDef(prefix = { "DISABLE_CAR_MODE_" }, value = {
+            DISABLE_CAR_MODE_GO_HOME
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisableCarMode {}
+
+    /**
+     * The default priority used for entering car mode.
+     * <p>
+     * Callers of the {@link UiModeManager#enableCarMode(int)} priority will be assigned the
+     * default priority.
+     * <p>
+     * System apps can specify a priority other than the default priority when using
+     * {@link UiModeManager#enableCarMode(int, int)} to enable car mode.
+     * @hide
+     */
+    @SystemApi
+    public static final int DEFAULT_PRIORITY = 0;
     
     /**
      * Turn off special mode if currently in car mode.
-     * @param flags May be 0 or {@link #DISABLE_CAR_MODE_GO_HOME}.
+     * @param flags One of the disable car mode flags.
      */
-    public void disableCarMode(int flags) {
+    public void disableCarMode(@DisableCarMode int flags) {
         if (mService != null) {
             try {
-                mService.disableCarMode(flags);
+                mService.disableCarModeByCallingPackage(flags,
+                        mContext == null ? null : mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 19f42b6..0be3eca 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1095,24 +1095,6 @@
     }
 
     /**
-     * Get the Bluetooth alias of the remote device.
-     * If Alias is null, get the Bluetooth name instead.
-     *
-     * @return the Bluetooth alias, or null if no alias or there was a problem
-     * @hide
-     * @see #getAlias()
-     * @see #getName()
-     */
-    @UnsupportedAppUsage(publicAlternatives = "Use {@link #getName()} instead.")
-    public String getAliasName() {
-        String name = getAlias();
-        if (name == null) {
-            name = getName();
-        }
-        return name;
-    }
-
-    /**
      * Get the most recent identified battery level of this Bluetooth device
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index cfb363a08..4e97627 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -16,8 +16,13 @@
 
 package android.bluetooth;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -25,6 +30,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -40,6 +47,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class BluetoothPan implements BluetoothProfile {
     private static final String TAG = "BluetoothPan";
     private static final boolean DBG = true;
@@ -67,6 +75,7 @@
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
      * receive.
      */
+    @SuppressLint("ActionValue")
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CONNECTION_STATE_CHANGED =
             "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
@@ -76,19 +85,32 @@
      * The local role of the PAN profile that the remote device is bound to.
      * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
      */
+    @SuppressLint("ActionValue")
     public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
 
+    /** @hide */
+    @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LocalPanRole {}
+
     public static final int PAN_ROLE_NONE = 0;
     /**
      * The local device is acting as a Network Access Point.
      */
     public static final int LOCAL_NAP_ROLE = 1;
-    public static final int REMOTE_NAP_ROLE = 1;
 
     /**
      * The local device is acting as a PAN User.
      */
     public static final int LOCAL_PANU_ROLE = 2;
+
+    /** @hide */
+    @IntDef({PAN_ROLE_NONE, REMOTE_NAP_ROLE, REMOTE_PANU_ROLE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RemotePanRole {}
+
+    public static final int REMOTE_NAP_ROLE = 1;
+
     public static final int REMOTE_PANU_ROLE = 2;
 
     /**
@@ -134,6 +156,8 @@
     /**
      * Create a BluetoothPan proxy object for interacting with the local
      * Bluetooth Service which handles the Pan profile
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     /*package*/ BluetoothPan(Context context, ServiceListener listener) {
@@ -235,7 +259,7 @@
      * {@inheritDoc}
      */
     @Override
-    public List<BluetoothDevice> getConnectedDevices() {
+    public @NonNull List<BluetoothDevice> getConnectedDevices() {
         if (VDBG) log("getConnectedDevices()");
         final IBluetoothPan service = getService();
         if (service != null && isEnabled()) {
@@ -252,6 +276,7 @@
 
     /**
      * {@inheritDoc}
+     * @hide
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
@@ -273,7 +298,7 @@
      * {@inheritDoc}
      */
     @Override
-    public int getConnectionState(BluetoothDevice device) {
+    public int getConnectionState(@Nullable BluetoothDevice device) {
         if (VDBG) log("getState(" + device + ")");
         final IBluetoothPan service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -288,7 +313,11 @@
         return BluetoothProfile.STATE_DISCONNECTED;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Turns on/off bluetooth tethering
+     *
+     * @param value is whether to enable or disable bluetooth tethering
+     */
     public void setBluetoothTethering(boolean value) {
         String pkgName = mContext.getOpPackageName();
         if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -302,7 +331,11 @@
         }
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Determines whether tethering is enabled
+     *
+     * @return true if tethering is on, false if not or some error occurred
+     */
     public boolean isTetheringOn() {
         if (VDBG) log("isTetheringOn()");
         final IBluetoothPan service = getService();
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index dabe0fd..f1ac765 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -20,9 +20,9 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -43,6 +43,7 @@
      * This extra represents the current connection state of the profile of the
      * Bluetooth device.
      */
+    @SuppressLint("ActionValue")
     String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
 
     /**
@@ -51,6 +52,7 @@
      * This extra represents the previous connection state of the profile of the
      * Bluetooth device.
      */
+    @SuppressLint("ActionValue")
     String EXTRA_PREVIOUS_STATE =
             "android.bluetooth.profile.extra.PREVIOUS_STATE";
 
@@ -106,7 +108,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @SystemApi
     int PAN = 5;
 
     /**
@@ -324,4 +326,54 @@
                 return "STATE_UNKNOWN";
         }
     }
+
+    /**
+     * Convert an integer value of profile ID into human readable string
+     *
+     * @param profile profile ID
+     * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined.
+     * @hide
+     */
+    static String getProfileName(int profile) {
+        switch(profile) {
+            case HEADSET:
+                return "HEADSET";
+            case A2DP:
+                return "A2DP";
+            case HID_HOST:
+                return "HID_HOST";
+            case PAN:
+                return "PAN";
+            case PBAP:
+                return "PBAP";
+            case GATT:
+                return "GATT";
+            case GATT_SERVER:
+                return "GATT_SERVER";
+            case MAP:
+                return "MAP";
+            case SAP:
+                return "SAP";
+            case A2DP_SINK:
+                return "A2DP_SINK";
+            case AVRCP_CONTROLLER:
+                return "AVRCP_CONTROLLER";
+            case AVRCP:
+                return "AVRCP";
+            case HEADSET_CLIENT:
+                return "HEADSET_CLIENT";
+            case PBAP_CLIENT:
+                return "PBAP_CLIENT";
+            case MAP_CLIENT:
+                return "MAP_CLIENT";
+            case HID_DEVICE:
+                return "HID_DEVICE";
+            case OPP:
+                return "OPP";
+            case HEARING_AID:
+                return "HEARING_AID";
+            default:
+                return "UNKNOWN_PROFILE";
+        }
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a12e4da..4b22166 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2424,10 +2424,10 @@
      *
      * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
      */
-    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
-            @Nullable String receiverPermission, @Nullable String receiverAppOp,
-            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
-            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+    public void sendOrderedBroadcast(@NonNull Intent intent, @Nullable String receiverPermission,
+            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -5256,8 +5256,9 @@
      */
     @SystemApi
     @TestApi
+    @NonNull
     public Context createPackageContextAsUser(
-            String packageName, @CreatePackageOptions int flags, UserHandle user)
+            @NonNull String packageName, @CreatePackageOptions int flags, @NonNull UserHandle user)
             throws PackageManager.NameNotFoundException {
         if (Build.IS_ENG) {
             throw new IllegalStateException("createPackageContextAsUser not overridden!");
@@ -5266,6 +5267,23 @@
     }
 
     /**
+     * Similar to {@link #createPackageContext(String, int)}, but for the own package with a
+     * different {@link UserHandle}. For example, {@link #getContentResolver()}
+     * will open any {@link Uri} as the given user.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @NonNull
+    public Context createContextAsUser(@NonNull UserHandle user, @CreatePackageOptions int flags) {
+        if (Build.IS_ENG) {
+            throw new IllegalStateException("createContextAsUser not overridden!");
+        }
+        return this;
+    }
+
+    /**
      * Creates a context given an {@link android.content.pm.ApplicationInfo}.
      *
      * @hide
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 2b1b8eb..428aadb 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -898,6 +898,12 @@
 
     /** @hide */
     @Override
+    public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+        return mBase.createContextAsUser(user, flags);
+    }
+
+    /** @hide */
+    @Override
     @UnsupportedAppUsage
     public Context createApplicationContext(ApplicationInfo application,
             int flags) throws PackageManager.NameNotFoundException {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3cecd7f..1099d8b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1565,7 +1565,7 @@
         }
 
         /** {@hide} */
-        @SystemApi
+        @SystemApi @TestApi
         public void setRequestDowngrade(boolean requestDowngrade) {
             if (requestDowngrade) {
                 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 28d9152..ce5fc3b 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -415,6 +415,17 @@
             @ResolveInfoFlags int flags, int filterCallingUid, int userId);
 
     /**
+     * Retrieve all activities that can be performed for the given intent.
+     * @param filterCallingUid The results will be filtered in the context of this UID instead
+     * of the calling UID.
+     * @see PackageManager#queryIntentActivities(Intent, int)
+     */
+    public abstract List<ResolveInfo> queryIntentActivities(
+            Intent intent, @Nullable String resolvedType, @ResolveInfoFlags int flags,
+            int filterCallingUid, int userId);
+
+
+    /**
      * Retrieve all services that can be performed for the given intent.
      * @see PackageManager#queryIntentServices(Intent, int)
      */
@@ -879,12 +890,6 @@
             "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
 
     /**
-     * Extra field name for the set of installed users for a given rollback package.
-     */
-    public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
-            "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
-
-    /**
      * Extra field name for the user id an install is associated with when
      * enabling rollback.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5c5c13d..c53b644 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -254,6 +254,8 @@
 
     /** @hide */
     public static final String APK_FILE_EXTENSION = ".apk";
+    /** @hide */
+    public static final String APEX_FILE_EXTENSION = ".apex";
 
     /** @hide */
     public static class NewPermissionInfo {
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 1b84f29..8c2a65f 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -24,7 +24,7 @@
 interface IRollbackManager {
 
     ParceledListSlice getAvailableRollbacks();
-    ParceledListSlice getRecentlyExecutedRollbacks();
+    ParceledListSlice getRecentlyCommittedRollbacks();
 
     void commitRollback(int rollbackId, in ParceledListSlice causePackages,
             String callerPackageName, in IntentSender statusReceiver);
@@ -51,4 +51,7 @@
     // Used by the staging manager to notify the RollbackManager of the apk
     // session for a staged session.
     void notifyStagedApkSession(int originalSessionId, int apkSessionId);
+
+    // For test purposes only.
+    void blockRollbackManager(long millis);
 }
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 2014751..c89796d 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -76,10 +76,10 @@
     private final boolean mIsApex;
 
     /*
-     * The list of users the package is installed for.
+     * The list of users for which snapshots have been saved.
      */
     // NOTE: Not a part of the Parcelable representation of this object.
-    private final IntArray mInstalledUsers;
+    private final IntArray mSnapshottedUsers;
 
     /**
      * A mapping between user and an inode of theirs CE data snapshot.
@@ -148,8 +148,8 @@
     }
 
     /** @hide */
-    public IntArray getInstalledUsers() {
-        return mInstalledUsers;
+    public IntArray getSnapshottedUsers() {
+        return mSnapshottedUsers;
     }
 
     /** @hide */
@@ -179,14 +179,14 @@
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
             @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
-            boolean isApex, @NonNull IntArray installedUsers,
+            boolean isApex, @NonNull IntArray snapshottedUsers,
             @NonNull SparseLongArray ceSnapshotInodes) {
         this.mVersionRolledBackFrom = packageRolledBackFrom;
         this.mVersionRolledBackTo = packageRolledBackTo;
         this.mPendingBackups = pendingBackups;
         this.mPendingRestores = pendingRestores;
         this.mIsApex = isApex;
-        this.mInstalledUsers = installedUsers;
+        this.mSnapshottedUsers = snapshottedUsers;
         this.mCeSnapshotInodes = ceSnapshotInodes;
     }
 
@@ -196,7 +196,7 @@
         this.mIsApex = in.readBoolean();
         this.mPendingRestores = null;
         this.mPendingBackups = null;
-        this.mInstalledUsers = null;
+        this.mSnapshottedUsers = null;
         this.mCeSnapshotInodes = null;
     }
 
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9a10a0c..73b8a48 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -114,7 +114,7 @@
     })
     public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
         try {
-            return mBinder.getRecentlyExecutedRollbacks().getList();
+            return mBinder.getRecentlyCommittedRollbacks().getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -250,4 +250,25 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Block the RollbackManager for a specified amount of time.
+     * This API is meant to facilitate testing of race conditions in
+     * RollbackManager. Blocks RollbackManager from processing anything for
+     * the given number of milliseconds.
+     *
+     * @param millis number of milliseconds to block the RollbackManager for
+     * @throws SecurityException if the caller does not have appropriate permissions.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
+    @TestApi
+    public void blockRollbackManager(long millis) {
+        try {
+            mBinder.blockRollbackManager(millis);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 75af41c..56bacf2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -52,13 +52,12 @@
 import android.os.ServiceSpecificException;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
@@ -711,6 +710,12 @@
     @Deprecated
     public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
 
+    // Deprecated constants for return values of startUsingNetworkFeature. They used to live
+    // in com.android.internal.telephony.PhoneConstants until they were made inaccessible.
+    private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0;
+    private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1;
+    private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3;
+
     /** {@hide} */
     public static final int MAX_RADIO_TYPE = TYPE_TEST;
 
@@ -1407,7 +1412,7 @@
         if (netCap == null) {
             Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
                     feature);
-            return PhoneConstants.APN_REQUEST_FAILED;
+            return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
         }
 
         NetworkRequest request = null;
@@ -1417,9 +1422,9 @@
                 Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest);
                 renewRequestLocked(l);
                 if (l.currentNetwork != null) {
-                    return PhoneConstants.APN_ALREADY_ACTIVE;
+                    return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE;
                 } else {
-                    return PhoneConstants.APN_REQUEST_STARTED;
+                    return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
                 }
             }
 
@@ -1427,10 +1432,10 @@
         }
         if (request != null) {
             Log.d(TAG, "starting startUsingNetworkFeature for request " + request);
-            return PhoneConstants.APN_REQUEST_STARTED;
+            return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
         } else {
             Log.d(TAG, " request Failed");
-            return PhoneConstants.APN_REQUEST_FAILED;
+            return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
         }
     }
 
@@ -2149,19 +2154,14 @@
     @Deprecated
     @UnsupportedAppUsage
     public boolean getMobileDataEnabled() {
-        IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE);
-        if (b != null) {
-            try {
-                ITelephony it = ITelephony.Stub.asInterface(b);
-                int subId = SubscriptionManager.getDefaultDataSubscriptionId();
-                Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
-                boolean retVal = it.isUserDataEnabled(subId);
-                Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
-                        + " retVal=" + retVal);
-                return retVal;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        if (tm != null) {
+            int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+            Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
+            boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled();
+            Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
+                    + " retVal=" + retVal);
+            return retVal;
         }
         Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
         return false;
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 2af82d7..143467b 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -16,6 +16,10 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.StaticIpConfiguration;
 import android.os.Parcel;
@@ -27,13 +31,17 @@
  * A class representing a configured network.
  * @hide
  */
-public class IpConfiguration implements Parcelable {
+@SystemApi
+public final class IpConfiguration implements Parcelable {
     private static final String TAG = "IpConfiguration";
 
+    // This enum has been used by apps through reflection for many releases.
+    // Therefore they can't just be removed. Duplicating these constants to
+    // give an alternate SystemApi is a worse option than exposing them.
+    @SuppressLint("Enum")
     public enum IpAssignment {
         /* Use statically configured IP settings. Configuration can be accessed
          * with staticIpConfiguration */
-        @UnsupportedAppUsage
         STATIC,
         /* Use dynamically configured IP settings */
         DHCP,
@@ -42,14 +50,19 @@
         UNASSIGNED
     }
 
+    /** @hide */
     public IpAssignment ipAssignment;
 
+    /** @hide */
     public StaticIpConfiguration staticIpConfiguration;
 
+    // This enum has been used by apps through reflection for many releases.
+    // Therefore they can't just be removed. Duplicating these constants to
+    // give an alternate SystemApi is a worse option than exposing them.
+    @SuppressLint("Enum")
     public enum ProxySettings {
         /* No proxy is to be used. Any existing proxy settings
          * should be cleared. */
-        @UnsupportedAppUsage
         NONE,
         /* Use statically configured proxy. Configuration can be accessed
          * with httpProxy. */
@@ -62,8 +75,10 @@
         PAC
     }
 
+    /** @hide */
     public ProxySettings proxySettings;
 
+    /** @hide */
     @UnsupportedAppUsage
     public ProxyInfo httpProxy;
 
@@ -83,6 +98,7 @@
         init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
     }
 
+    /** @hide */
     @UnsupportedAppUsage
     public IpConfiguration(IpAssignment ipAssignment,
                            ProxySettings proxySettings,
@@ -91,7 +107,7 @@
         init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
     }
 
-    public IpConfiguration(IpConfiguration source) {
+    public IpConfiguration(@NonNull IpConfiguration source) {
         this();
         if (source != null) {
             init(source.ipAssignment, source.proxySettings,
@@ -99,35 +115,35 @@
         }
     }
 
-    public IpAssignment getIpAssignment() {
+    public @NonNull IpAssignment getIpAssignment() {
         return ipAssignment;
     }
 
-    public void setIpAssignment(IpAssignment ipAssignment) {
+    public void setIpAssignment(@NonNull IpAssignment ipAssignment) {
         this.ipAssignment = ipAssignment;
     }
 
-    public StaticIpConfiguration getStaticIpConfiguration() {
+    public @Nullable StaticIpConfiguration getStaticIpConfiguration() {
         return staticIpConfiguration;
     }
 
-    public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
+    public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) {
         this.staticIpConfiguration = staticIpConfiguration;
     }
 
-    public ProxySettings getProxySettings() {
+    public @NonNull ProxySettings getProxySettings() {
         return proxySettings;
     }
 
-    public void setProxySettings(ProxySettings proxySettings) {
+    public void setProxySettings(@NonNull ProxySettings proxySettings) {
         this.proxySettings = proxySettings;
     }
 
-    public ProxyInfo getHttpProxy() {
+    public @Nullable ProxyInfo getHttpProxy() {
         return httpProxy;
     }
 
-    public void setHttpProxy(ProxyInfo httpProxy) {
+    public void setHttpProxy(@Nullable ProxyInfo httpProxy) {
         this.httpProxy = httpProxy;
     }
 
@@ -175,13 +191,19 @@
                83 * httpProxy.hashCode();
     }
 
-    /** Implement the Parcelable interface */
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
     public int describeContents() {
         return 0;
     }
 
-    /** Implement the Parcelable interface  */
-    public void writeToParcel(Parcel dest, int flags) {
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
         dest.writeParcelable(staticIpConfiguration, flags);
@@ -189,7 +211,7 @@
     }
 
     /** Implement the Parcelable interface */
-    public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR =
+    public static final @NonNull Creator<IpConfiguration> CREATOR =
         new Creator<IpConfiguration>() {
             public IpConfiguration createFromParcel(Parcel in) {
                 IpConfiguration config = new IpConfiguration();
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index a101da7..9af1407 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -16,17 +16,20 @@
 
 package android.net;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -48,6 +51,13 @@
     /** A wifi network, for which {@link #wifiKey} will be populated. */
     public static final int TYPE_WIFI = 1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"TYPE_"}, value = {
+            TYPE_WIFI
+    })
+    public @interface NetworkType {}
+
     /**
      * The type of this network.
      * @see #TYPE_WIFI
@@ -65,26 +75,28 @@
      *
      * @return  A new {@link NetworkKey} instance or <code>null</code> if the given
      *          {@link ScanResult} instance is malformed.
-     * @hide
      */
     @Nullable
     public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
-        if (result != null && result.wifiSsid != null) {
-            final String ssid = result.wifiSsid.toString();
-            final String bssid = result.BSSID;
-            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
-                    && !TextUtils.isEmpty(bssid)) {
-                WifiKey wifiKey;
-                try {
-                    wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
-                } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Unable to create WifiKey.", e);
-                    return null;
-                }
-                return new NetworkKey(wifiKey);
-            }
+        if (result == null) {
+            return null;
         }
-        return null;
+        final String ssid = result.SSID;
+        if (TextUtils.isEmpty(ssid) || ssid.equals(WifiManager.UNKNOWN_SSID)) {
+            return null;
+        }
+        final String bssid = result.BSSID;
+        if (TextUtils.isEmpty(bssid)) {
+            return null;
+        }
+
+        try {
+            final WifiKey wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid);
+            return new NetworkKey(wifiKey);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Unable to create WifiKey.", e);
+            return null;
+        }
     }
 
     /**
@@ -100,7 +112,7 @@
         if (wifiInfo != null) {
             final String ssid = wifiInfo.getSSID();
             final String bssid = wifiInfo.getBSSID();
-            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE)
+            if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiManager.UNKNOWN_SSID)
                     && !TextUtils.isEmpty(bssid)) {
                 WifiKey wifiKey;
                 try {
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index 1ab6335..13f2994 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -154,4 +154,9 @@
         }
         return true;
     }
+
+    /** Convert to a string */
+    public String toString() {
+        return "NetworkScore[" + mExtensions.toString() + "]";
+    }
 }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 50dd468..f6dc525 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -17,7 +17,9 @@
 package android.net;
 
 import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -25,13 +27,16 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Class that manages communication between network subsystems and a network scorer.
@@ -50,19 +55,25 @@
 @SystemApi
 @SystemService(Context.NETWORK_SCORE_SERVICE)
 public class NetworkScoreManager {
+    private static final String TAG = "NetworkScoreManager";
+
     /**
      * Activity action: ask the user to change the active network scorer. This will show a dialog
      * that asks the user whether they want to replace the current active scorer with the one
      * specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
      * active scorer was changed or RESULT_CANCELED if it failed for any reason.
+     * @deprecated No longer sent.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
 
     /**
      * Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
      * {@link android.content.Intent#putExtra(String, String)}.
+     * @deprecated No longer sent.
      */
+    @Deprecated
     public static final String EXTRA_PACKAGE_NAME = "packageName";
 
     /**
@@ -73,7 +84,9 @@
      * configured by the user as well as any open networks.
      *
      * <p class="note">This is a protected intent that can only be sent by the system.
+     * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
 
@@ -81,7 +94,9 @@
      * Extra used with {@link #ACTION_SCORE_NETWORKS} to specify the networks to be scored, as an
      * array of {@link NetworkKey}s. Can be obtained with
      * {@link android.content.Intent#getParcelableArrayExtra(String)}}.
+     * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
      */
+    @Deprecated
     public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
 
     /**
@@ -285,7 +300,7 @@
      * @throws SecurityException if the caller is not the active scorer.
      */
     @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
-    public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
+    public boolean updateScores(@NonNull ScoredNetwork[] networks) throws SecurityException {
         try {
             return mService.updateScores(networks);
         } catch (RemoteException e) {
@@ -359,13 +374,21 @@
     /**
      * Request scoring for networks.
      *
-     * @return true if the broadcast was sent, or false if there is no active scorer.
+     * <p>
+     * Note: The results (i.e scores) for these networks, when available will be provided via the
+     * callback registered with {@link #registerNetworkScoreCallback(int, int, Executor,
+     * NetworkScoreCallback)}. The calling module is responsible for registering a callback to
+     * receive the results before requesting new scores via this API.
+     *
+     * @return true if the request was successfully sent, or false if there is no active scorer.
      * @throws SecurityException if the caller does not hold the
      *         {@link permission#REQUEST_NETWORK_SCORES} permission.
+     *
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
-    public boolean requestScores(NetworkKey[] networks) throws SecurityException {
+    public boolean requestScores(@NonNull NetworkKey[] networks) throws SecurityException {
         try {
             return mService.requestScores(networks);
         } catch (RemoteException e) {
@@ -431,6 +454,88 @@
     }
 
     /**
+     * Base class for network score cache callback. Should be extended by applications and set
+     * when calling {@link #registerNetworkScoreCallback(int, int, NetworkScoreCallback,
+     * Executor)}
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface NetworkScoreCallback {
+        /**
+         * Called when a new set of network scores are available.
+         * This is triggered in response when the client invokes
+         * {@link #requestScores(NetworkKey[])} to score a new set of networks.
+         *
+         * @param networks List of {@link ScoredNetwork} containing updated scores.
+         */
+        void updateScores(@NonNull List<ScoredNetwork> networks);
+
+        /**
+         * Invokes when all the previously provided scores are no longer valid.
+         */
+        void clearScores();
+    }
+
+    /**
+     * Callback proxy for {@link NetworkScoreCallback} objects.
+     */
+    private class NetworkScoreCallbackProxy extends INetworkScoreCache.Stub {
+        private final Executor mExecutor;
+        private final NetworkScoreCallback mCallback;
+
+        NetworkScoreCallbackProxy(Executor executor, NetworkScoreCallback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void updateScores(@NonNull List<ScoredNetwork> networks) {
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
+                mCallback.updateScores(networks);
+            });
+        }
+
+        @Override
+        public void clearScores() {
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
+                mCallback.clearScores();
+            });
+        }
+    }
+
+    /**
+     * Register a network score callback.
+     *
+     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
+     * @param filterType the {@link CacheUpdateFilter} to apply
+     * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the
+     *                 scores change.
+     * @param executor The executor on which to execute the callbacks.
+     * @throws SecurityException if the caller does not hold the
+     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
+     * @throws IllegalArgumentException if a callback is already registered for this type.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
+    public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType,
+            @CacheUpdateFilter int filterType,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull NetworkScoreCallback callback) throws SecurityException {
+        if (callback == null || executor == null) {
+            throw new IllegalArgumentException("callback / executor cannot be null");
+        }
+        Log.v(TAG, "registerNetworkScoreCallback: callback=" + callback + ", executor="
+                + executor);
+        // Use the @hide method.
+        registerNetworkScoreCache(
+                networkType, new NetworkScoreCallbackProxy(executor, callback), filterType);
+    }
+
+    /**
      * Determine whether the application with the given UID is the enabled scorer.
      *
      * @param callingUid the UID to check
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 807c467..9d92db4 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -16,7 +16,8 @@
 
 package android.net;
 
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -89,6 +90,15 @@
     }
 
     /**
+     * Construct a {@link ProxyInfo} object that will download and run the PAC script at the
+     * specified URL and port.
+     */
+    @NonNull
+    public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) {
+        return new ProxyInfo(pacUrl, port);
+    }
+
+    /**
      * Create a ProxyProperties that points at a HTTP Proxy.
      * @hide
      */
@@ -105,7 +115,7 @@
      * Create a ProxyProperties that points at a PAC URL.
      * @hide
      */
-    public ProxyInfo(Uri pacFileUrl) {
+    public ProxyInfo(@NonNull Uri pacFileUrl) {
         mHost = LOCAL_HOST;
         mPort = LOCAL_PORT;
         mExclusionList = LOCAL_EXCL_LIST;
@@ -132,7 +142,7 @@
      * Only used in PacManager after Local Proxy is bound.
      * @hide
      */
-    public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
+    public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
         mHost = LOCAL_HOST;
         mPort = localProxyPort;
         mExclusionList = LOCAL_EXCL_LIST;
@@ -159,11 +169,10 @@
         mPacFileUrl = Uri.EMPTY;
     }
 
-    // copy constructor instead of clone
     /**
-     * @hide
+     * A copy constructor to hold proxy properties.
      */
-    public ProxyInfo(ProxyInfo source) {
+    public ProxyInfo(@Nullable ProxyInfo source) {
         if (source != null) {
             mHost = source.getHost();
             mPort = source.getPort();
@@ -226,12 +235,13 @@
      * comma separated
      * @hide
      */
+    @Nullable
     public String getExclusionListAsString() {
         return mExclusionList;
     }
 
     /**
-     * @hide
+     * Return true if the pattern of proxy is valid, otherwise return false.
      */
     public boolean isValid() {
         if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f789b72..2ac3def 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1275,7 +1275,13 @@
     /**
      * Closes the given object quietly, ignoring any checked exceptions. Does
      * nothing if the given object is {@code null}.
+     *
+     * @deprecated This method may suppress potentially significant exceptions, particularly when
+     *   closing writable resources. With a writable resource, a failure thrown from {@code close()}
+     *   should be considered as significant as a failure thrown from a write method because it may
+     *   indicate a failure to flush bytes to the underlying resource.
      */
+    @Deprecated
     public static void closeQuietly(@Nullable AutoCloseable closeable) {
         IoUtils.closeQuietly(closeable);
     }
@@ -1283,7 +1289,13 @@
     /**
      * Closes the given object quietly, ignoring any checked exceptions. Does
      * nothing if the given object is {@code null}.
+     *
+     * @deprecated This method may suppress potentially significant exceptions, particularly when
+     *   closing writable resources. With a writable resource, a failure thrown from {@code close()}
+     *   should be considered as significant as a failure thrown from a write method because it may
+     *   indicate a failure to flush bytes to the underlying resource.
      */
+    @Deprecated
     public static void closeQuietly(@Nullable FileDescriptor fd) {
         IoUtils.closeQuietly(fd);
     }
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 9af9eda..a99bdabe 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -28,15 +28,14 @@
  * A Handler allows you to send and process {@link Message} and Runnable
  * objects associated with a thread's {@link MessageQueue}.  Each Handler
  * instance is associated with a single thread and that thread's message
- * queue.  When you create a new Handler, it is bound to the thread /
- * message queue of the thread that is creating it -- from that point on,
- * it will deliver messages and runnables to that message queue and execute
- * them as they come out of the message queue.
- * 
+ * queue. When you create a new Handler it is bound to a {@link Looper}.
+ * It will deliver messages and runnables to that Looper's message
+ * queue and execute them on that Looper's thread.
+ *
  * <p>There are two main uses for a Handler: (1) to schedule messages and
  * runnables to be executed at some point in the future; and (2) to enqueue
  * an action to be performed on a different thread than your own.
- * 
+ *
  * <p>Scheduling messages is accomplished with the
  * {@link #post}, {@link #postAtTime(Runnable, long)},
  * {@link #postDelayed}, {@link #sendEmptyMessage},
@@ -114,7 +113,18 @@
      *
      * If this thread does not have a looper, this handler won't be able to receive messages
      * so an exception is thrown.
+     *
+     * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
+     *   where operations are silently lost (if the Handler is not expecting new tasks and quits),
+     *   crashes (if a handler is sometimes created on a thread without a Looper active), or race
+     *   conditions, where the thread a handler is associated with is not what the author
+     *   anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper
+     *   explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or
+     *   similar. If the implicit thread local behavior is required for compatibility, use
+     *   {@code new Handler(Looper.myLooper())} to make it clear to readers.
+     *
      */
+    @Deprecated
     public Handler() {
         this(null, false);
     }
@@ -128,7 +138,17 @@
      * so an exception is thrown.
      *
      * @param callback The callback interface in which to handle messages, or null.
+     *
+     * @deprecated Implicitly choosing a Looper during Handler construction can lead to bugs
+     *   where operations are silently lost (if the Handler is not expecting new tasks and quits),
+     *   crashes (if a handler is sometimes created on a thread without a Looper active), or race
+     *   conditions, where the thread a handler is associated with is not what the author
+     *   anticipated. Instead, use an {@link java.util.concurrent.Executor} or specify the Looper
+     *   explicitly, using {@link Looper#getMainLooper}, {link android.view.View#getHandler}, or
+     *   similar. If the implicit thread local behavior is required for compatibility, use
+     *   {@code new Handler(Looper.myLooper(), callback)} to make it clear to readers.
      */
+    @Deprecated
     public Handler(@Nullable Callback callback) {
         this(callback, false);
     }
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
new file mode 100644
index 0000000..aeb6589
--- /dev/null
+++ b/core/java/android/os/HidlMemory.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * An abstract representation of a memory block, as representing by the HIDL system.
+ *
+ * The block is defined by a {name, size, handle} tuple, where the name is used to determine how to
+ * interpret the handle. The underlying handle is assumed to be owned by this instance and will be
+ * closed as soon as {@link #close()} is called on this instance, or this instance has been
+ * finalized (the latter supports using it in a shared manner without having to worry about who owns
+ * this instance, the former is more efficient resource-wise and is recommended for most use-cases).
+ * Note, however, that ownership of the handle does not necessarily imply ownership of the
+ * underlying file descriptors - the underlying handle may or may not own them. If you want the
+ * underlying handle to outlive this instance, call {@link #releaseHandle()} to obtain the handle
+ * and detach the ownership relationship.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class HidlMemory implements Closeable {
+    private final @NonNull String mName;
+    private final long mSize;
+    private @Nullable NativeHandle mHandle;
+    private long mNativeContext;  // For use of native code.
+
+    /**
+     * Constructor.
+     *
+     * @param name      The name of the IMapper service used to resolve the handle (e.g. "ashmem").
+     * @param size      The (non-negative) size in bytes of the memory block.
+     * @param handle    The handle. May be null. This instance will own the handle and will close it
+     *                  as soon as {@link #close()} is called or the object is destroyed. This, this
+     *                  handle instance should generally not be shared with other clients.
+     */
+    public HidlMemory(@NonNull String name, @IntRange(from = 0) long size,
+            @Nullable NativeHandle handle) {
+        mName = name;
+        mSize = size;
+        mHandle = handle;
+    }
+
+    /**
+     * Create a copy of this instance, where the underlying handle (and its file descriptors) have
+     * been duplicated.
+     */
+    @NonNull
+    public HidlMemory dup() throws IOException {
+        return new HidlMemory(mName, mSize, mHandle != null ? mHandle.dup() : null);
+    }
+
+    /**
+     * Close the underlying native handle. No-op if handle is null or has been released using {@link
+     * #releaseHandle()}.
+     */
+    @Override
+    public void close() throws IOException {
+        if (mHandle != null) {
+            mHandle.close();
+        }
+    }
+
+    /**
+     * Disowns the underlying handle and returns it. This object becomes invalid.
+     *
+     * @return The underlying handle.
+     */
+    @NonNull
+    public NativeHandle releaseHandle() {
+        NativeHandle handle = mHandle;
+        mHandle = null;
+        return handle;
+    }
+
+    /**
+     * Gets the name, which represents how the handle is to be interpreted.
+     *
+     * @return The name.
+     */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the size of the block, in bytes.
+     *
+     * @return The size.
+     */
+    public long getSize() {
+        return mSize;
+    }
+
+    /**
+     * Gets a native handle. The actual interpretation depends on the name and is implementation
+     * defined.
+     *
+     * @return The native handle.
+     */
+    @Nullable
+    public NativeHandle getHandle() {
+        return mHandle;
+    }
+
+    @Override
+    protected void finalize() {
+        try {
+            close();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            nativeFinalize();
+        }
+    }
+
+    private native void nativeFinalize();
+}
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java
new file mode 100644
index 0000000..b08822d
--- /dev/null
+++ b/core/java/android/os/HidlMemoryUtil.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import static android.system.OsConstants.MAP_SHARED;
+import static android.system.OsConstants.PROT_READ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides utilities for dealing with HidlMemory.
+ *
+ * @hide
+ */
+public final class HidlMemoryUtil {
+    static private final String TAG = "HidlMemoryUtil";
+
+    private HidlMemoryUtil() {
+    }
+
+    /**
+     * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+     * The returned instance owns the underlying file descriptors, and the client should generally
+     * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+     * be closed).
+     *
+     * @param input The input byte array.
+     * @return A HidlMemory instance, containing a copy of the input.
+     */
+    public static @NonNull
+    HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) {
+        return byteArrayToHidlMemory(input, null);
+    }
+
+    /**
+     * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+     * The returned instance owns the underlying file descriptors, and the client should generally
+     * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+     * be closed).
+     *
+     * @param input The input byte array.
+     * @param name  An optional name for the ashmem region.
+     * @return A HidlMemory instance, containing a copy of the input.
+     */
+    public static @NonNull
+    HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) {
+        Preconditions.checkNotNull(input);
+
+        if (input.length == 0) {
+            return new HidlMemory("ashmem", 0, null);
+        }
+
+        try {
+            SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length);
+            ByteBuffer buffer = shmem.mapReadWrite();
+            buffer.put(input);
+            shmem.unmap(buffer);
+            NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+            return new HidlMemory("ashmem", input.length, handle);
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+     * The returned instance owns the underlying file descriptors, and the client should generally
+     * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+     * be closed).
+     *
+     * @param input The input byte list.
+     * @return A HidlMemory instance, containing a copy of the input.
+     */
+    public static @NonNull
+    HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) {
+        return byteListToHidlMemory(input, null);
+    }
+
+    /**
+     * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+     * The returned instance owns the underlying file descriptors, and the client should generally
+     * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+     * be closed).
+     *
+     * @param input The input byte list.
+     * @param name  An optional name for the ashmem region.
+     * @return A HidlMemory instance, containing a copy of the input.
+     */
+    public static @NonNull
+    HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) {
+        Preconditions.checkNotNull(input);
+
+        if (input.isEmpty()) {
+            return new HidlMemory("ashmem", 0, null);
+        }
+
+        try {
+            SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size());
+            ByteBuffer buffer = shmem.mapReadWrite();
+            for (Byte b : input) {
+                buffer.put(b);
+            }
+            shmem.unmap(buffer);
+            NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+            return new HidlMemory("ashmem", input.size(), handle);
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Copies all data from a HidlMemory instance into a byte array.
+     *
+     * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+     *            {@link Integer#MAX_VALUE}.
+     * @return A byte array, containing a copy of the input.
+     */
+    public static @NonNull
+    byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) {
+        Preconditions.checkNotNull(mem);
+        Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+                "Memory size");
+        Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+                "Unsupported memory type: %s", mem.getName());
+
+        if (mem.getSize() == 0) {
+            return new byte[0];
+        }
+
+        ByteBuffer buffer = getBuffer(mem);
+        byte[] result = new byte[buffer.remaining()];
+        buffer.get(result);
+        return result;
+    }
+
+    /**
+     * Copies all data from a HidlMemory instance into a byte list.
+     *
+     * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+     *            {@link Integer#MAX_VALUE}.
+     * @return A byte list, containing a copy of the input.
+     */
+    @SuppressLint("ConcreteCollection")
+    public static @NonNull
+    ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) {
+        Preconditions.checkNotNull(mem);
+        Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+                "Memory size");
+        Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+                "Unsupported memory type: %s", mem.getName());
+
+        if (mem.getSize() == 0) {
+            return new ArrayList<>();
+        }
+
+        ByteBuffer buffer = getBuffer(mem);
+
+        ArrayList<Byte> result = new ArrayList<>(buffer.remaining());
+        while (buffer.hasRemaining()) {
+            result.add(buffer.get());
+        }
+        return result;
+    }
+
+    private static ByteBuffer getBuffer(@NonNull HidlMemory mem) {
+        try {
+            final int size = (int) mem.getSize();
+
+            if (size == 0) {
+                return ByteBuffer.wrap(new byte[0]);
+            }
+
+            NativeHandle handle = mem.getHandle();
+
+            final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(),
+                    0);
+            return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> {
+                try {
+                    Os.munmap(address, size);
+                } catch (ErrnoException e) {
+                    Log.wtf(TAG, e);
+                }
+            }, true);
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 2c453bf..154227b2 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -92,6 +92,14 @@
      * @throws IndexOutOfBoundsException when offset is out of this HwBlob
      */
     public native final String getString(long offset);
+    /**
+     * For embedded fields that follow a two-step approach for reading, first obtain their field
+     * handle using this method, and pass that field handle to the respective
+     * HwParcel.readEmbedded*() method.
+     * @param offset The field offset.
+     * @return The field handle.
+     */
+    public native final long getFieldHandle(long offset);
 
     /**
      * Copy the blobs data starting from the given byte offset into the range, copying
@@ -312,6 +320,20 @@
     public native final void putBlob(long offset, HwBlob blob);
 
     /**
+     * Writes a HidlMemory instance (without duplicating the underlying file descriptors) at an
+     * offset.
+     *
+     * @param offset location to write value
+     * @param mem    a {@link HidlMemory} instance to write
+     * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
+     */
+    public final void putHidlMemory(long offset, @NonNull HidlMemory mem) {
+        putNativeHandle(offset + 0  /* offset of 'handle' field. */, mem.getHandle());
+        putInt64(offset + 16  /* offset of 'size' field. */, mem.getSize());
+        putString(offset + 24  /* offset of 'name' field. */, mem.getName());
+    }
+
+    /**
      * @return current handle of HwBlob for reference in a parcelled binder transaction
      */
     public native final long handle();
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 5e8929c..9786f16 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -324,6 +324,15 @@
     public native final void writeStrongBinder(IHwBinder binder);
 
     /**
+     * Write a HidlMemory object (without duplicating the underlying file descriptors) to the end
+     * of the parcel.
+     *
+     * @param memory value to write
+     */
+    @FastNative
+    public native final void writeHidlMemory(@NonNull HidlMemory memory);
+
+    /**
      * Checks to make sure that the interface name matches the name written by the parcel
      * sender by writeInterfaceToken
      *
@@ -582,6 +591,38 @@
     public native final IHwBinder readStrongBinder();
 
     /**
+     * Reads a HidlMemory value (without duplicating the underlying file
+     * descriptors) from the parcel. These file descriptors will only
+     * be open for the duration that the binder window is open. If they
+     * are needed further, you must call {@link HidlMemory#dup()}, which makes you also
+     * responsible for calling {@link HidlMemory#close()}.
+     *
+     * @return HidlMemory object read from parcel.
+     * @throws IllegalArgumentException if the parcel has no more data or is otherwise corrupt.
+     */
+    @FastNative
+    @NonNull
+    public native final HidlMemory readHidlMemory();
+
+    /**
+     * Reads an embedded HidlMemory (without duplicating the underlying
+     * file descriptors) from the parcel. These file descriptors will only
+     * be open for the duration that the binder window is open. If they
+     * are needed further, you must call {@link HidlMemory#dup()}. You
+     * do not need to call close on the HidlMemory returned from this.
+     *
+     * @param fieldHandle  handle of the field, obtained from the {@link HwBlob}.
+     * @param parentHandle parentHandle from which to read the embedded object
+     * @param offset       offset into parent
+     * @return a {@link HidlMemory} instance parsed from the parcel
+     * @throws IllegalArgumentException if the parcel has no more data
+     */
+    @FastNative
+    @NonNull
+    public native final @Nullable
+    HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
+
+    /**
      * Read opaque segment of data as a blob.
      * @return blob of size expectedSize
      * @throws IllegalArgumentException if the parcel has no more data
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 3222fc4..d468972 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -112,10 +112,12 @@
 
     /**
      * Initialize the current thread as a looper, marking it as an
-     * application's main looper. The main looper for your application
-     * is created by the Android environment, so you should never need
-     * to call this function yourself.  See also: {@link #prepare()}
+     * application's main looper. See also: {@link #prepare()}
+     *
+     * @deprecated The main looper for your application is created by the Android environment,
+     *   so you should never need to call this function yourself.
      */
+    @Deprecated
     public static void prepareMainLooper() {
         prepare(false);
         synchronized (Looper.class) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 8b0ffe1..f08e1ff 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -26,6 +26,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 import libcore.util.HexEncoding;
 
 import java.nio.charset.StandardCharsets;
@@ -93,18 +96,43 @@
         }
     }
 
+    // The one-argument version of native_get used to be a regular native function. Nowadays,
+    // we use the two-argument form of native_get all the time, but we can't just delete the
+    // one-argument overload: apps use it via reflection, as the UnsupportedAppUsage annotation
+    // indicates. Let's just live with having a Java function with a very unusual name.
     @UnsupportedAppUsage
-    private static native String native_get(String key);
+    private static String native_get(String key) {
+        return native_get(key, "");
+    }
+
+    @FastNative
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native String native_get(String key, String def);
+    @FastNative
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native int native_get_int(String key, int def);
+    @FastNative
     @UnsupportedAppUsage
     private static native long native_get_long(String key, long def);
+    @FastNative
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native boolean native_get_boolean(String key, boolean def);
+
+    @FastNative
+    private static native long native_find(String name);
+    @FastNative
+    private static native String native_get(long handle);
+    @CriticalNative
+    private static native int native_get_int(long handle, int def);
+    @CriticalNative
+    private static native long native_get_long(long handle, long def);
+    @CriticalNative
+    private static native boolean native_get_boolean(long handle, boolean def);
+
+    // _NOT_ FastNative: native_set performs IPC and can block
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native void native_set(String key, String def);
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static native void native_add_change_callback();
     private static native void native_report_sysprop_change();
@@ -229,25 +257,27 @@
 
     @SuppressWarnings("unused")  // Called from native code.
     private static void callChangeCallbacks() {
+        ArrayList<Runnable> callbacks = null;
         synchronized (sChangeCallbacks) {
             //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
             if (sChangeCallbacks.size() == 0) {
                 return;
             }
-            ArrayList<Runnable> callbacks = new ArrayList<Runnable>(sChangeCallbacks);
-            final long token = Binder.clearCallingIdentity();
-            try {
-                for (int i = 0; i < callbacks.size(); i++) {
-                    try {
-                        callbacks.get(i).run();
-                    } catch (Throwable t) {
-                        Log.wtf(TAG, "Exception in SystemProperties change callback", t);
-                        // Ignore and try to go on.
-                    }
+            callbacks = new ArrayList<Runnable>(sChangeCallbacks);
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            for (int i = 0; i < callbacks.size(); i++) {
+                try {
+                    callbacks.get(i).run();
+                } catch (Throwable t) {
+                    // Ignore and try to go on. Don't use wtf here: that
+                    // will cause the process to exit on some builds and break tests.
+                    Log.e(TAG, "Exception in SystemProperties change callback", t);
                 }
-            } finally {
-                Binder.restoreCallingIdentity(token);
             }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
@@ -284,4 +314,60 @@
     @UnsupportedAppUsage
     private SystemProperties() {
     }
+
+    /**
+     * Look up a property location by name.
+     * @name name of the property
+     * @return property handle or {@code null} if property isn't set
+     * @hide
+     */
+    @Nullable public static Handle find(@NonNull String name) {
+        long nativeHandle = native_find(name);
+        if (nativeHandle == 0) {
+            return null;
+        }
+        return new Handle(nativeHandle);
+    }
+
+    /**
+     * Handle to a pre-located property. Looking up a property handle in advance allows
+     * for optimal repeated lookup of a single property.
+     * @hide
+     */
+    public static final class Handle {
+
+        private final long mNativeHandle;
+
+        /**
+         * @return Value of the property
+         */
+        @NonNull public String get() {
+            return native_get(mNativeHandle);
+        }
+        /**
+         * @param def default value
+         * @return value or {@code def} on parse error
+         */
+        public int getInt(int def) {
+            return native_get_int(mNativeHandle, def);
+        }
+        /**
+         * @param def default value
+         * @return value or {@code def} on parse error
+         */
+        public long getLong(long def) {
+            return native_get_long(mNativeHandle, def);
+        }
+        /**
+         * @param def default value
+         * @return value or {@code def} on parse error
+         */
+        public boolean getBoolean(boolean def) {
+            return native_get_boolean(mNativeHandle, def);
+        }
+
+        private Handle(long nativeHandle) {
+            mNativeHandle = nativeHandle;
+        }
+    }
 }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 82a3c40..391f3a2 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -43,8 +43,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.internal.telephony.PhoneConstants;
-
 import java.util.List;
 
 /**
@@ -610,7 +608,7 @@
          * if the contact is unknown.
          * @param context the context used to get the ContentResolver
          * @param number the phone number to be added to the calls db
-         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+         * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
          * @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -645,7 +643,7 @@
          * @param number the phone number to be added to the calls db
          * @param viaNumber the secondary number that the incoming call received with. If the
          *       call was received with the SIM assigned number, then this field must be ''.
-         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+         * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
          * @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -686,7 +684,7 @@
          *        if it was outgoing. Otherwise it is ''.
          * @param viaNumber the secondary number that the incoming call received with. If the
          *        call was received with the SIM assigned number, then this field must be ''.
-         * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
+         * @param presentation enum value from TelecomManager.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
          * @param callType enumerated values for "incoming", "outgoing", or "missed"
@@ -1048,22 +1046,22 @@
 
         /**
          * Remap network specified number presentation types
-         * PhoneConstants.PRESENTATION_xxx to calllog number presentation types
+         * TelecomManager.PRESENTATION_xxx to calllog number presentation types
          * Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
          * from any future radio changes.
          * If the number field is empty set the presentation type to Unknown.
          */
         private static int getLogNumberPresentation(String number, int presentation) {
-            if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
+            if (presentation == TelecomManager.PRESENTATION_RESTRICTED) {
                 return presentation;
             }
 
-            if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
+            if (presentation == TelecomManager.PRESENTATION_PAYPHONE) {
                 return presentation;
             }
 
             if (TextUtils.isEmpty(number)
-                    || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
+                    || presentation == TelecomManager.PRESENTATION_UNKNOWN) {
                 return PRESENTATION_UNKNOWN;
             }
 
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 2af827e..a65c8fd 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -184,7 +184,8 @@
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
     /**
-     * Listen for {@link PreciseCallState.State} of ringing, background and foreground calls.
+     * Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+     * background and foreground calls.
      *
      * @hide
      */
diff --git a/telephony/java/android/telephony/Rlog.java b/core/java/android/telephony/Rlog.java
similarity index 100%
rename from telephony/java/android/telephony/Rlog.java
rename to core/java/android/telephony/Rlog.java
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 456789fb..5c42730 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -29,13 +29,13 @@
 import android.os.HandlerExecutor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telephony.Annotation;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.CallState;
 import android.telephony.Annotation.DataActivityType;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.DataState;
 import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
@@ -43,7 +43,6 @@
 import android.telephony.CellInfo;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneCapability;
-import android.telephony.PreciseCallState.State;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
@@ -624,8 +623,10 @@
      *
      * @hide
      */
-    public void notifyPreciseCallState(int subId, int slotIndex, @State int ringCallPreciseState,
-        @State int foregroundCallPreciseState, @State int backgroundCallPreciseState) {
+    public void notifyPreciseCallState(int subId, int slotIndex,
+        @PreciseCallStates int ringCallPreciseState,
+        @PreciseCallStates int foregroundCallPreciseState,
+        @PreciseCallStates int backgroundCallPreciseState) {
         try {
             sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
                 foregroundCallPreciseState, backgroundCallPreciseState);
diff --git a/core/java/android/util/TimingLogger.java b/core/java/android/util/TimingLogger.java
index be442da..5a4a512 100644
--- a/core/java/android/util/TimingLogger.java
+++ b/core/java/android/util/TimingLogger.java
@@ -44,7 +44,14 @@
  *     D/TAG     ( 3459): methodA:      6 ms, work C
  *     D/TAG     ( 3459): methodA: end, 16 ms
  * </pre>
+ *
+ * @deprecated Use {@link android.os.Trace}, or
+ *   <a href="https://developer.android.com/studio/profile/benchmark">Android Studio</a>. In
+ *   general, milliseconds is the wrong granularity for method-level tracing. Rounding errors
+ *   can overemphasize cheap operations, or underemphasize repeated operations. This timing
+ *   system also does not take CPU scheduling or frequency into account.
  */
+@Deprecated
 public class TimingLogger {
 
     /**
diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java
index 7943c61..d44312b 100644
--- a/core/java/com/android/internal/app/DisableCarModeActivity.java
+++ b/core/java/com/android/internal/app/DisableCarModeActivity.java
@@ -33,7 +33,9 @@
         try {
             IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface(
                     ServiceManager.getService("uimode"));
-            uiModeManager.disableCarMode(UiModeManager.DISABLE_CAR_MODE_GO_HOME);
+            uiModeManager.disableCarModeByCallingPackage(UiModeManager.DISABLE_CAR_MODE_GO_HOME
+                            | UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES,
+                    getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to disable car mode", e);
         }
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index aef4dbf..e3d07aa 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -208,7 +208,7 @@
      * @return the maximized Locale instance.
      */
     public static Locale addLikelySubtags(Locale locale) {
-        return libcore.icu.ICU.addLikelySubtags(locale);
+        return ULocale.addLikelySubtags(ULocale.forLocale(locale)).toLocale();
     }
 
     /**
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 045a680..7dcb12c 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -171,6 +171,15 @@
     void clearOverrides(in String packageName);
 
     /**
+     * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+     *
+     * @param packageName The package name of the app whose overrides will be cleared.
+     *
+     */
+    void clearOverridesForTest(in String packageName);
+
+
+    /**
      * Get configs for an application.
      *
      * @param appInfo The application whose config will be returned.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 486d24c..7b61277 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -87,6 +87,7 @@
         "android_text_Hyphenator.cpp",
         "android_os_Debug.cpp",
         "android_os_GraphicsEnvironment.cpp",
+        "android_os_HidlMemory.cpp",
         "android_os_HidlSupport.cpp",
         "android_os_HwBinder.cpp",
         "android_os_HwBlob.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9e4c222..2383731 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -191,6 +191,7 @@
 extern int register_android_os_Trace(JNIEnv* env);
 extern int register_android_os_FileObserver(JNIEnv *env);
 extern int register_android_os_UEventObserver(JNIEnv* env);
+extern int register_android_os_HidlMemory(JNIEnv* env);
 extern int register_android_os_MemoryFile(JNIEnv* env);
 extern int register_android_os_SharedMemory(JNIEnv* env);
 extern int register_android_net_LocalSocketImpl(JNIEnv* env);
@@ -1474,6 +1475,7 @@
     REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_os_Parcel),
+    REG_JNI(register_android_os_HidlMemory),
     REG_JNI(register_android_os_HidlSupport),
     REG_JNI(register_android_os_HwBinder),
     REG_JNI(register_android_os_HwBlob),
diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp
new file mode 100644
index 0000000..69e4818
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android_os_HidlMemory.h"
+#include "core_jni_helpers.h"
+#include "android_os_NativeHandle.h"
+
+#define PACKAGE_PATH    "android/os"
+#define CLASS_NAME      "HidlMemory"
+#define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+namespace {
+
+static struct {
+    jclass clazz;
+    jfieldID nativeContext;  // long
+    jmethodID constructor;   // HidlMemory(String, long, NativeHandle)
+    jmethodID getName;       // String HidlMemory.getName()
+    jmethodID getSize;       // int HidlMemory.getSize()
+    jmethodID getHandle;     // NativeHandle HidlMemory.getHandle()
+} gFields;
+
+std::string stringFromJava(JNIEnv* env, jstring jstr) {
+    ScopedUtfChars s(env, jstr);
+    return s.c_str();
+}
+
+jstring stringToJava(JNIEnv* env, const std::string& cstr) {
+    return env->NewStringUTF(cstr.c_str());
+}
+
+static void nativeFinalize(JNIEnv* env, jobject jobj) {
+    jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+    JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+    delete native;
+}
+
+static JNINativeMethod gMethods[] = {
+        {"nativeFinalize", "()V", (void*) nativeFinalize},
+};
+
+}  // namespace
+
+JHidlMemory::~JHidlMemory() {
+    if (mObj) {
+        // Must manually delete the underlying handle - hidl_memory doesn't own
+        // it.
+        native_handle_delete(const_cast<native_handle_t*>(mObj->handle()));
+    }
+}
+
+/* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env,
+                                                                jobject jobj) {
+    // Try to get the result from cache.
+    env->MonitorEnter(jobj);
+    JHidlMemory* obj = getNativeContext(env, jobj);
+    if (!obj->mObj) {
+        // Create and cache.
+        obj->mObj = javaToNative(env, jobj);
+    }
+    env->MonitorExit(jobj);
+    return obj->mObj.get();
+}
+
+/* static */ jobject JHidlMemory::toJava(JNIEnv* env,
+                                         const hardware::hidl_memory& cobj) {
+    if (cobj.size() > std::numeric_limits<jlong>::max()) {
+        return nullptr;
+    }
+    jstring jname = stringToJava(env, cobj.name());
+    jlong jsize = static_cast<jlong>(cobj.size());
+    jobject jhandle =
+            JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle());
+
+    // We're sharing the handle of cobj, so the Java instance doesn't own it.
+    return env->NewObject(gFields.clazz,
+                          gFields.constructor,
+                          jname,
+                          jsize,
+                          jhandle,
+                          false);
+}
+
+/* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative(
+        JNIEnv* env,
+        jobject jobj) {
+    jstring jname =
+            static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName));
+    jlong jsize = env->CallLongMethod(jobj, gFields.getSize);
+    jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle);
+
+    if (jsize > std::numeric_limits<size_t>::max()) {
+        return nullptr;
+    }
+
+    std::string cname = stringFromJava(env, jname);
+    size_t csize = jsize;
+    // We created the handle here, we're responsible to call
+    // native_handle_delete() on it. However, we don't assume ownership of the
+    // underlying fd, so we shouldn't call native_handle_close() on it.
+    native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle,
+                                                                  nullptr);
+    // hidl_memory doesn't take ownership of the handle here, so won't delete
+    // or close it.
+    return std::make_unique<hardware::hidl_memory>(cname, chandle, csize);
+}
+
+/* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env,
+                                                        jobject jobj) {
+    env->MonitorEnter(jobj);
+    jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+    JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+    if (!native) {
+        native = new JHidlMemory();
+        env->SetLongField(jobj,
+                          gFields.nativeContext,
+                          reinterpret_cast<jlong>(native));
+    }
+    env->MonitorExit(jobj);
+    return native;
+}
+
+int register_android_os_HidlMemory(JNIEnv* env) {
+    jclass clazz = FindClassOrDie(env, CLASS_PATH);
+    gFields.clazz = MakeGlobalRefOrDie(env, clazz);
+
+    gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
+
+    gFields.constructor = GetMethodIDOrDie(env,
+                                           clazz,
+                                           "<init>",
+                                           "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V");
+    gFields.getName =
+            GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
+    gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J");
+    gFields.getHandle = GetMethodIDOrDie(env,
+                                         clazz,
+                                         "getHandle",
+                                         "()L" PACKAGE_PATH "/NativeHandle;");
+
+    RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+
+    return 0;
+}
+
+}  // namespace android
+
diff --git a/core/jni/android_os_HidlMemory.h b/core/jni/android_os_HidlMemory.h
new file mode 100644
index 0000000..993a132
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_OS_HIDL_MEMORY_H
+#define ANDROID_OS_HIDL_MEMORY_H
+
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+
+// A utility class for handling the android.os.HidlMemory class from JNI code.
+class JHidlMemory final {
+ public:
+    // Convert an android.os.HidlMemory object to its C++ counterpart,
+    // hardware::hidl_memory.
+    // No duplication of file descriptors is performed.
+    // The returned reference is owned by the underlying Java object.
+    // Returns nullptr if conversion cannot be done.
+    static const hardware::hidl_memory* fromJava(JNIEnv* env,
+                                                 jobject jobj);
+
+    // Convert a hardware::hidl_memory object to its Java counterpart,
+    // android.os.HidlMemory.
+    // No duplication of file descriptors is performed.
+    // Returns nullptr if conversion cannot be done.
+    static jobject toJava(JNIEnv* env,
+                          const hardware::hidl_memory& cobj);
+
+    ~JHidlMemory();
+
+ private:
+    // We store an instance of type JHidlMemory attached to every Java object
+    // of type HidlMemory, for holding any native context we need. This instance
+    // will get deleted when finalize() is called on the Java object.
+    // This method either extracts the native object from the Java object, or
+    // attached a new one if it doesn't yet exist.
+    static JHidlMemory* getNativeContext(JNIEnv* env, jobject obj);
+
+    // Convert an android.os.HidlMemory object to its C++ counterpart,
+    // hardware::hidl_memory.
+    // No duplication of file descriptors is performed.
+    // IMPORTANT: caller is responsible to native_handle_delete() the handle of the
+    // returned object. This is due to an underlying limitation of the hidl_handle
+    // type, where ownership of the handle implies ownership of the fd and we don't
+    // want the latter.
+    // Returns nullptr if conversion cannot be done.
+    static std::unique_ptr<hardware::hidl_memory> javaToNative(JNIEnv* env,
+                                                               jobject jobj);
+
+    std::unique_ptr<hardware::hidl_memory> mObj;
+};
+
+int register_android_os_HidlMemory(JNIEnv* env);
+
+}  // namespace android
+
+#endif //ANDROID_OS_HIDL_MEMORY_H
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index e5b72ca..0fb2911 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -340,6 +340,14 @@
     return env->NewStringUTF(s->c_str());
 }
 
+static jlong JHwBlob_native_getFieldHandle(JNIEnv* env,
+                                           jobject thiz,
+                                           jlong offset) {
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    return reinterpret_cast<jlong>(blob->data()) + offset;
+}
+
 #define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType)                          \
 static void JHwBlob_native_copyTo ## Suffix ## Array(                          \
         JNIEnv *env,                                                           \
@@ -593,6 +601,7 @@
     { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
     { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
     { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+    { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle},
 
     { "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
     { "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index f437a78..151dbfc 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -20,6 +20,7 @@
 
 #include "android_os_HwParcel.h"
 
+#include "android_os_HidlMemory.h"
 #include "android_os_HwBinder.h"
 #include "android_os_HwBlob.h"
 #include "android_os_NativeHandle.h"
@@ -27,6 +28,8 @@
 
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
@@ -650,6 +653,36 @@
     signalExceptionForError(env, err);
 }
 
+static void JHwParcel_native_writeHidlMemory(
+    JNIEnv *env, jobject thiz, jobject jmem) {
+
+    if (jmem == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        return;
+    }
+
+    status_t err = OK;
+
+    // Convert the Java object to its C++ counterpart.
+    const hardware::hidl_memory* cmem = JHidlMemory::fromJava(env, jmem);
+    if (cmem == nullptr) {
+        err = BAD_VALUE;
+    }
+
+    if (err == OK) {
+        // Write it to the parcel.
+        hardware::Parcel* parcel =
+            JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+        size_t parentHandle;
+        err = parcel->writeBuffer(cmem, sizeof(*cmem), &parentHandle);
+        if (err == OK) {
+            err = hardware::writeEmbeddedToParcel(*cmem, parcel, parentHandle, 0);
+        }
+    }
+    signalExceptionForError(env, err);
+}
+
 static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
     String16 utf16String(s.c_str(), s.size());
 
@@ -877,6 +910,74 @@
     return objArray;
 }
 
+static status_t readEmbeddedHidlMemory(JNIEnv* env,
+                                       hardware::Parcel* parcel,
+                                       const hardware::hidl_memory& mem,
+                                       size_t parentHandle,
+                                       size_t parentOffset,
+                                       jobject* result) {
+    status_t err = hardware::readEmbeddedFromParcel(mem,
+                                                    *parcel,
+                                                    parentHandle,
+                                                    parentOffset);
+    if (err == OK) {
+        // Convert to Java.
+        *result = JHidlMemory::toJava(env, mem);
+        if (*result == nullptr) {
+            err = BAD_VALUE;
+        }
+    }
+    return err;
+}
+
+static jobject JHwParcel_native_readHidlMemory(
+        JNIEnv* env, jobject thiz) {
+    hardware::Parcel* parcel =
+            JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    jobject result = nullptr;
+
+    const hardware::hidl_memory* mem;
+    size_t parentHandle;
+
+    status_t err = parcel->readBuffer(sizeof(*mem),
+                                      &parentHandle,
+                                      reinterpret_cast<const void**>(&mem));
+    if (err == OK) {
+        err = readEmbeddedHidlMemory(env,
+                                     parcel,
+                                     *mem,
+                                     parentHandle,
+                                     0,
+                                     &result);
+    }
+
+    signalExceptionForError(env, err);
+    return result;
+}
+
+static jobject JHwParcel_native_readEmbeddedHidlMemory(
+        JNIEnv* env,
+        jobject thiz,
+        jlong fieldHandle,
+        jlong parentHandle,
+        jlong offset) {
+    hardware::Parcel* parcel =
+            JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    jobject result = nullptr;
+    const hardware::hidl_memory* mem =
+            reinterpret_cast<const hardware::hidl_memory*>(fieldHandle);
+    status_t err = readEmbeddedHidlMemory(env,
+                                          parcel,
+                                          *mem,
+                                          parentHandle,
+                                          offset,
+                                          &result);
+    signalExceptionForError(env, err);
+    return result;
+}
+
 static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
     hardware::Parcel *parcel =
         JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -1075,6 +1176,14 @@
     { "release", "()V",
         (void *)JHwParcel_native_release },
 
+    {"writeHidlMemory", "(L" PACKAGE_PATH "/HidlMemory;)V",
+     (void*) JHwParcel_native_writeHidlMemory},
+
+    {"readHidlMemory", "()L" PACKAGE_PATH "/HidlMemory;",
+     (void*) JHwParcel_native_readHidlMemory},
+
+    {"readEmbeddedHidlMemory", "(JJJ)L" PACKAGE_PATH "/HidlMemory;",
+     (void*) JHwParcel_native_readEmbeddedHidlMemory},
 };
 
 namespace android {
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 87f498a..7f3b32e 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -17,9 +17,13 @@
 
 #define LOG_TAG "SysPropJNI"
 
+#include <utility>
+#include <optional>
+
 #include "android-base/logging.h"
+#include "android-base/parsebool.h"
+#include "android-base/parseint.h"
 #include "android-base/properties.h"
-#include "cutils/properties.h"
 #include "utils/misc.h"
 #include <utils/Log.h>
 #include "jni.h"
@@ -28,86 +32,171 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
 
-namespace android
-{
+#if defined(__BIONIC__)
+# include <sys/system_properties.h>
+#else
+struct prop_info;
+#endif
 
+namespace android {
 namespace {
 
-template <typename T, typename Handler>
-T ConvertKeyAndForward(JNIEnv *env, jstring keyJ, T defJ, Handler handler) {
-    std::string key;
-    {
-        // Scope the String access. If the handler can throw an exception,
-        // releasing the string characters late would trigger an abort.
-        ScopedUtfChars key_utf(env, keyJ);
-        if (key_utf.c_str() == nullptr) {
-            return defJ;
-        }
-        key = key_utf.c_str();  // This will make a copy, but we can't avoid
-                                // with the existing interface in
-                                // android::base.
-    }
-    return handler(key, defJ);
+using android::base::ParseBoolResult;
+
+template<typename Functor>
+void ReadProperty(const prop_info* prop, Functor&& functor)
+{
+#if defined(__BIONIC__)
+    auto thunk = [](void* cookie,
+                    const char* /*name*/,
+                    const char* value,
+                    uint32_t /*serial*/) {
+        std::forward<Functor>(*static_cast<Functor*>(cookie))(value);
+    };
+    __system_property_read_callback(prop, thunk, &functor);
+#else
+    LOG(FATAL) << "fast property access supported only on device";
+#endif
 }
 
-jstring SystemProperties_getSS(JNIEnv *env, jclass clazz, jstring keyJ,
+template<typename Functor>
+void ReadProperty(JNIEnv* env, jstring keyJ, Functor&& functor)
+{
+    ScopedUtfChars key(env, keyJ);
+    if (!key.c_str()) {
+        return;
+    }
+#if defined(__BIONIC__)
+    const prop_info* prop = __system_property_find(key.c_str());
+    if (!prop) {
+        return;
+    }
+    ReadProperty(prop, std::forward<Functor>(functor));
+#else
+    std::forward<Functor>(functor)(
+        android::base::GetProperty(key.c_str(), "").c_str());
+#endif
+}
+
+jstring SystemProperties_getSS(JNIEnv* env, jclass clazz, jstring keyJ,
                                jstring defJ)
 {
-    // Using ConvertKeyAndForward is sub-optimal for copying the key string,
-    // but improves reuse and reasoning over code.
-    auto handler = [&](const std::string& key, jstring defJ) {
-        std::string prop_val = android::base::GetProperty(key, "");
-        if (!prop_val.empty()) {
-            return env->NewStringUTF(prop_val.c_str());
-        };
-        if (defJ != nullptr) {
-            return defJ;
+    jstring ret = defJ;
+    ReadProperty(env, keyJ, [&](const char* value) {
+        if (value[0]) {
+            ret = env->NewStringUTF(value);
         }
-        // This function is specified to never return null (or have an
-        // exception pending).
-        return env->NewStringUTF("");
-    };
-    return ConvertKeyAndForward(env, keyJ, defJ, handler);
-}
-
-jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ)
-{
-    return SystemProperties_getSS(env, clazz, keyJ, nullptr);
+    });
+    if (ret == nullptr && !env->ExceptionCheck()) {
+      ret = env->NewStringUTF("");  // Legacy behavior
+    }
+    return ret;
 }
 
 template <typename T>
 T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
                                        T defJ)
 {
-    auto handler = [](const std::string& key, T defV) {
-        return android::base::GetIntProperty<T>(key, defV);
-    };
-    return ConvertKeyAndForward(env, keyJ, defJ, handler);
+    T ret = defJ;
+    ReadProperty(env, keyJ, [&](const char* value) {
+        android::base::ParseInt<T>(value, &ret);
+    });
+    return ret;
+}
+
+static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolean defJ) {
+    jboolean ret;
+    switch (parseResult) {
+        case ParseBoolResult::kError:
+            ret = defJ;
+            break;
+        case ParseBoolResult::kFalse:
+            ret = JNI_FALSE;
+            break;
+        case ParseBoolResult::kTrue:
+            ret = JNI_TRUE;
+            break;
+    }
+    return ret;
 }
 
 jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
                                       jboolean defJ)
 {
-    auto handler = [](const std::string& key, jboolean defV) -> jboolean {
-        bool result = android::base::GetBoolProperty(key, defV);
-        return result ? JNI_TRUE : JNI_FALSE;
-    };
-    return ConvertKeyAndForward(env, keyJ, defJ, handler);
+    ParseBoolResult parseResult = ParseBoolResult::kError;
+    ReadProperty(env, keyJ, [&](const char* value) {
+        parseResult = android::base::ParseBool(value);
+    });
+    return jbooleanFromParseBoolResult(parseResult, defJ);
+}
+
+jlong SystemProperties_find(JNIEnv* env, jclass, jstring keyJ)
+{
+#if defined(__BIONIC__)
+    ScopedUtfChars key(env, keyJ);
+    if (!key.c_str()) {
+        return 0;
+    }
+    const prop_info* prop = __system_property_find(key.c_str());
+    return reinterpret_cast<jlong>(prop);
+#else
+    LOG(FATAL) << "fast property access supported only on device";
+    __builtin_unreachable();  // Silence warning
+#endif
+}
+
+jstring SystemProperties_getH(JNIEnv* env, jclass clazz, jlong propJ)
+{
+    jstring ret;
+    auto prop = reinterpret_cast<const prop_info*>(propJ);
+    ReadProperty(prop, [&](const char* value) {
+        ret = env->NewStringUTF(value);
+    });
+    return ret;
+}
+
+template <typename T>
+T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ)
+{
+    T ret = defJ;
+    auto prop = reinterpret_cast<const prop_info*>(propJ);
+    ReadProperty(prop, [&](const char* value) {
+        android::base::ParseInt<T>(value, &ret);
+    });
+    return ret;
+}
+
+jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ)
+{
+    ParseBoolResult parseResult = ParseBoolResult::kError;
+    auto prop = reinterpret_cast<const prop_info*>(propJ);
+    ReadProperty(prop, [&](const char* value) {
+        parseResult = android::base::ParseBool(value);
+    });
+    return jbooleanFromParseBoolResult(parseResult, defJ);
 }
 
 void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
                           jstring valJ)
 {
-    auto handler = [&](const std::string& key, bool) {
-        std::string val;
-        if (valJ != nullptr) {
-            ScopedUtfChars key_utf(env, valJ);
-            val = key_utf.c_str();
+    ScopedUtfChars key(env, keyJ);
+    if (!key.c_str()) {
+        return;
+    }
+    std::optional<ScopedUtfChars> value;
+    if (valJ != nullptr) {
+        value.emplace(env, valJ);
+        if (!value->c_str()) {
+            return;
         }
-        return android::base::SetProperty(key, val);
-    };
-    if (!ConvertKeyAndForward(env, keyJ, true, handler)) {
-        // Must have been a failure in SetProperty.
+    }
+    bool success;
+#if defined(__BIONIC__)
+    success = !__system_property_set(key.c_str(), value ? value->c_str() : "");
+#else
+    success = android::base::SetProperty(key.c_str(), value ? value->c_str() : "");
+#endif
+    if (!success) {
         jniThrowException(env, "java/lang/RuntimeException",
                           "failed to set system property (check logcat for reason)");
     }
@@ -157,8 +246,6 @@
 int register_android_os_SystemProperties(JNIEnv *env)
 {
     const JNINativeMethod method_table[] = {
-        { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
-          (void*) SystemProperties_getS },
         { "native_get",
           "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
           (void*) SystemProperties_getSS },
@@ -168,6 +255,18 @@
           (void*) SystemProperties_get_integral<jlong> },
         { "native_get_boolean", "(Ljava/lang/String;Z)Z",
           (void*) SystemProperties_get_boolean },
+        { "native_find",
+          "(Ljava/lang/String;)J",
+          (void*) SystemProperties_find },
+        { "native_get",
+          "(J)Ljava/lang/String;",
+          (void*) SystemProperties_getH },
+        { "native_get_int", "(JI)I",
+          (void*) SystemProperties_get_integralH<jint> },
+        { "native_get_long", "(JJ)J",
+          (void*) SystemProperties_get_integralH<jlong> },
+        { "native_get_boolean", "(JZ)Z",
+          (void*) SystemProperties_get_booleanH },
         { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
           (void*) SystemProperties_set },
         { "native_add_change_callback", "()V",
@@ -179,4 +278,4 @@
                                 method_table, NELEM(method_table));
 }
 
-};
+}  // namespace android
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 3704ccd..8fabb23 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -34,6 +34,7 @@
 // Static whitelist of open paths that the zygote is allowed to keep open.
 static const char* kPathWhitelist[] = {
   "/apex/com.android.conscrypt/javalib/conscrypt.jar",
+  "/apex/com.android.ipsec/javalib/ike.jar",
   "/apex/com.android.media/javalib/updatable-media.jar",
   "/dev/null",
   "/dev/socket/zygote",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index c023438..6bf4c43 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2401,4 +2401,11 @@
     // OS: Q
     // Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
     SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
+    // ---- End Q Constants, all Q constants go above this line ----
+
+    // OPEN: Settings > Developer Options > Platform Compat
+    // CATEGORY: SETTINGS
+    // OS: R
+    SETTINGS_PLATFORM_COMPAT_DASHBOARD = 1805;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 74b4f34..216b87f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -108,6 +108,8 @@
 
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
+    <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIVILEGED" />
+    <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIVILEGED" />
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
@@ -4339,6 +4341,21 @@
          it will be ignored.
         @hide -->
     <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
+      android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
+        This permission is required to use UiModeManager while specifying a priority for the calling
+        app.  A device manufacturer uses this permission to prioritize the apps which can
+        potentially request to enter car-mode on a device to help establish the correct behavior
+        where multiple such apps are active at the same time.
+        @hide -->
+    <permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"
+                android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Required to receive ACTION_ENTER_CAR_MODE_PRIVILEGED or
+        ACTION_EXIT_CAR_MODE_PRIVILEGED.
+        @hide -->
+    <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
                 android:protectionLevel="signature|privileged" />
 
     <!-- The system process is explicitly the only one allowed to launch the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84d4857..4b4baa9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -529,7 +529,7 @@
 
              - TYPE_ETHERNET (9) is prepended to this list, and
 
-             - the return value of TelephonyManager.isTetherApnRequired()
+             - the return value of TelephonyManager.isTetheringApnRequired()
                determines how the array is further modified:
 
                    * TRUE (DUN REQUIRED).
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index 0f1c71d..c6c0b46 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -22,7 +22,7 @@
 
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiSsid;
+import android.net.wifi.WifiManager;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -65,7 +65,7 @@
 
     @Test
     public void createFromWifi_noneSsid() throws Exception {
-        when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+        when(mWifiInfo.getSSID()).thenReturn(WifiManager.UNKNOWN_SSID);
         when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID);
         assertNull(NetworkKey.createFromWifiInfo(mWifiInfo));
     }
@@ -106,7 +106,7 @@
     }
 
     @Test
-    public void createFromScanResult_nullWifiSsid() {
+    public void createFromScanResult_nullSsid() {
         ScanResult scanResult = new ScanResult();
         scanResult.BSSID = VALID_BSSID;
 
@@ -114,18 +114,18 @@
     }
 
     @Test
-    public void createFromScanResult_emptyWifiSsid() {
+    public void createFromScanResult_emptySsid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded("");
+        scanResult.SSID = "";
         scanResult.BSSID = VALID_BSSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
     }
 
     @Test
-    public void createFromScanResult_noneWifiSsid() {
+    public void createFromScanResult_noneSsid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(WifiSsid.NONE);
+        scanResult.SSID = WifiManager.UNKNOWN_SSID;
         scanResult.BSSID = VALID_BSSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -134,7 +134,7 @@
     @Test
     public void createFromScanResult_nullBssid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.SSID = VALID_UNQUOTED_SSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
     }
@@ -142,7 +142,7 @@
     @Test
     public void createFromScanResult_emptyBssid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = "";
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
@@ -151,16 +151,16 @@
     @Test
     public void createFromScanResult_invalidBssid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = INVALID_BSSID;
 
         assertNull(NetworkKey.createFromScanResult(scanResult));
     }
 
     @Test
-    public void createFromScanResult_validWifiSsid() {
+    public void createFromScanResult_validSsid() {
         ScanResult scanResult = new ScanResult();
-        scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID);
+        scanResult.SSID = VALID_UNQUOTED_SSID;
         scanResult.BSSID = VALID_BSSID;
 
         NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID));
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 928351e..b48ac33 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -93,6 +93,27 @@
     }
 
     @SmallTest
+    private static void testHandle() throws Exception {
+        String value;
+        SystemProperties.Handle handle = SystemProperties.find("doesnotexist_2341431");
+        assertNull(handle);
+        SystemProperties.set(KEY, "abc");
+        handle = SystemProperties.find(KEY);
+        assertNotNull(handle);
+        value = handle.get();
+        assertEquals("abc", value);
+        SystemProperties.set(KEY, "blarg");
+        value = handle.get();
+        assertEquals("blarg", value);
+        SystemProperties.set(KEY, "1");
+        assertEquals(1, handle.getInt(-1));
+        assertEquals(1, handle.getLong(-1));
+        assertEquals(true, handle.getBoolean(false));
+        SystemProperties.set(KEY, "");
+        assertEquals(12345, handle.getInt(12345));
+    }
+
+    @SmallTest
     public void testIntegralProperties() throws Exception {
         testInt("", 123, 123);
         testInt("", 0, 0);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 80f3cc6..9064abf 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -238,6 +238,7 @@
         <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
         <permission name="android.permission.BIND_INCALL_SERVICE"/>
         <permission name="android.permission.CALL_PRIVILEGED"/>
+        <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MANAGE_ROLE_HOLDERS"/>
@@ -328,6 +329,8 @@
         <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
         <!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
         <permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/>
+        <!-- Permission required for UiModeManager cts test. -->
+        <permission name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 646aa13..c0a0422 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -348,16 +348,6 @@
         return list(prefix, UID_SELF);
     }
 
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public boolean reset() {
-        try {
-            return mBinder.reset() == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
-    }
-
     /**
      * Attempt to lock the keystore for {@code user}.
      *
@@ -922,15 +912,26 @@
         }
     }
 
-    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
-            byte[] entropy) {
+    /**
+     * Android KeyStore finish operation.
+     *
+     * @param token Authentication token.
+     * @param arguments Keymaster arguments
+     * @param input Optional additional input data.
+     * @param signature Optional signature to be verified.
+     * @param entropy Optional additional entropy
+     * @return OperationResult that will indicate success or error of the operation.
+     */
+    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
+            byte[] signature, byte[] entropy) {
         OperationPromise promise = new OperationPromise();
         try {
             mBinder.asBinder().linkToDeath(promise, 0);
             arguments = arguments != null ? arguments : new KeymasterArguments();
             entropy = entropy != null ? entropy : new byte[0];
+            input = input != null ? input : new byte[0];
             signature = signature != null ? signature : new byte[0];
-            int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
+            int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
             if (errorCode == NO_ERROR) {
                 return promise.getFuture().get();
             } else {
@@ -948,7 +949,7 @@
     }
 
     public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
-        return finish(token, arguments, signature, null);
+        return finish(token, arguments, null, signature, null);
     }
 
     private class KeystoreResultPromise
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 441ee66..c6515ef 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -432,7 +432,7 @@
         }
 
         @Override
-        public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
+        public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
             if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
                 throw new ProviderException("AAD stream does not support additional entropy");
             }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 3dc884e..17aacb9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -210,13 +210,9 @@
                     }
                 }
                 if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
-                    if (mKeySizeBits < 64) {
+                    if (mKeySizeBits < 64 || mKeySizeBits > 512) {
                         throw new InvalidAlgorithmParameterException(
-                            "HMAC key size must be at least 64 bits.");
-                    }
-                    if (mKeySizeBits > 512 && spec.isStrongBoxBacked()) {
-                        throw new InvalidAlgorithmParameterException(
-                            "StrongBox HMAC key size must be smaller than 512 bits.");
+                            "HMAC key sizes must be within 64-512 bits, inclusive.");
                     }
 
                     // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index e030478..75bea26 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -62,7 +62,7 @@
          * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
          * be reached.
          */
-        OperationResult finish(byte[] siganture, byte[] additionalEntropy);
+        OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy);
     }
 
     // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
@@ -217,7 +217,8 @@
         byte[] output = update(input, inputOffset, inputLength);
         output = ArrayUtils.concat(output, flush());
 
-        OperationResult opResult = mKeyStoreStream.finish(signature, additionalEntropy);
+        OperationResult opResult = mKeyStoreStream.finish(EmptyArray.BYTE, signature,
+                                                          additionalEntropy);
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
@@ -334,8 +335,8 @@
         }
 
         @Override
-        public OperationResult finish(byte[] signature, byte[] additionalEntropy) {
-            return mKeyStore.finish(mOperationToken, null, signature, additionalEntropy);
+        public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
+            return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy);
         }
     }
 }
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 8c38d88..84a0e0d 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -26,7 +26,6 @@
 #include <nativehelper/JNIHelp.h>
 
 #include <binder/MemoryDealer.h>
-#include <drm/drm_framework_common.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <nativehelper/ScopedLocalRef.h>
 
@@ -160,8 +159,4 @@
     return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
 }
 
-sp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) {
-    return NULL;
-}
-
 }  // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 39405d2..378baf4 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -47,7 +47,6 @@
     virtual void close();
     virtual uint32_t getFlags();
     virtual String8 toString();
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
 
 private:
     // Protect all member variables with mLock because this object will be
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
index 5d84d64..1928ad9 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
 
@@ -90,12 +89,10 @@
 
         Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
-        Rlog.d(TAG, "OnReceive redirection intent");
         mReceiver.onReceive(mContext, intent);
 
         mContext.waitForMs(100);
 
-        Rlog.d(TAG, "verify carrier action: showPortalNotification");
         verify(mNotificationMgr, times(1)).notify(mString.capture(), mInt.capture(),
                 mNotification.capture());
         assertEquals(PORTAL_NOTIFICATION_ID, (int) mInt.getValue());
@@ -103,7 +100,6 @@
         PendingIntent pendingIntent = mNotification.getValue().contentIntent;
         assertNotNull(pendingIntent);
 
-        Rlog.d(TAG, "verify carrier action: disable all metered apns");
         verify(mTelephonyMgr).setCarrierDataEnabled(eq(false));
     }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 047ac59..13fc881 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -207,6 +207,9 @@
     <!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
 
+    <!-- Permission requried for CTS test - UiModeManagerTest -->
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index f73ca1c..236f17e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -110,8 +110,7 @@
             mCallbacks.add(callback);
             if (mWifiManager != null) {
                 if (mCallbacks.size() == 1) {
-                    mWifiManager.registerSoftApCallback(this,
-                            new HandlerExecutor(mMainHandler));
+                    mWifiManager.registerSoftApCallback(new HandlerExecutor(mMainHandler), this);
                 } else {
                     // mWifiManager#registerSoftApCallback triggers a call to
                     // onConnectedClientsChanged on the Main Handler. In order to always update
@@ -120,6 +119,7 @@
                     mMainHandler.post(() ->
                             callback.onHotspotChanged(isHotspotEnabled(),
                                     mNumConnectedDevices));
+
                 }
             }
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 7496e3a..631c580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -70,11 +70,11 @@
         mContext.addMockSystemService(WifiManager.class, mWifiManager);
 
         doAnswer((InvocationOnMock invocation) -> {
-            ((WifiManager.SoftApCallback) invocation.getArgument(0))
+            ((WifiManager.SoftApCallback) invocation.getArgument(1))
                     .onConnectedClientsChanged(new ArrayList<>());
             return null;
-        }).when(mWifiManager).registerSoftApCallback(any(WifiManager.SoftApCallback.class),
-                any(Executor.class));
+        }).when(mWifiManager).registerSoftApCallback(any(Executor.class),
+                any(WifiManager.SoftApCallback.class));
 
         mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
     }
@@ -84,7 +84,7 @@
         mController.addCallback(mCallback1);
         mController.addCallback(mCallback2);
 
-        verify(mWifiManager, times(1)).registerSoftApCallback(eq(mController), any());
+        verify(mWifiManager, times(1)).registerSoftApCallback(any(), eq(mController));
     }
 
     @Test
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 61bfb92..7b35f4d 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -20,12 +20,14 @@
     srcs: [
         "src/**/*.java",
         ":framework-tethering-shared-srcs",
+        ":net-module-utils-srcs",
         ":services-tethering-shared-srcs",
         ":servicescore-tethering-src",
     ],
     static_libs: [
         "androidx.annotation_annotation",
         "netd_aidl_interface-java",
+        "netlink-client",
         "networkstack-aidl-interfaces-java",
         "android.hardware.tetheroffload.control-V1.0-java",
         "tethering-client",
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index cf0e3b2..ca9b168 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -251,7 +251,7 @@
     /** Check whether dun is required. */
     public static boolean checkDunRequired(Context ctx, int id) {
         final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
-        return (tm != null) ? tm.isTetherApnRequired(id) : false;
+        return (tm != null) ? tm.isTetheringApnRequired(id) : false;
     }
 
     private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 9c65c0d..30bff35 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -145,7 +145,7 @@
 
     @Test
     public void testDunFromTelephonyManagerMeansDun() {
-        when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(true);
+        when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(true);
 
         final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
         final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -169,7 +169,7 @@
 
     @Test
     public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
-        when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+        when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
 
         final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
         final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -212,7 +212,7 @@
     @Test
     public void testNoDefinedUpstreamTypesAddsEthernet() {
         when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{});
-        when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+        when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
 
         final TetheringConfiguration cfg = new TetheringConfiguration(
                 mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -235,7 +235,7 @@
     public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
         when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(
                 new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
-        when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+        when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
 
         final TetheringConfiguration cfg = new TetheringConfiguration(
                 mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -253,7 +253,7 @@
     public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
         when(mResources.getIntArray(config_tether_upstream_types))
                 .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
-        when(mTelephonyManager.isTetherApnRequired(anyInt())).thenReturn(false);
+        when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false);
 
         final TetheringConfiguration cfg = new TetheringConfiguration(
                 mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a05c2cc..084a747 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -32,6 +32,7 @@
         "android.hardware.power-V1.0-java",
         "android.hardware.tv.cec-V1.0-java",
         "app-compat-annotations",
+        "vintf-vibrator-java",
     ],
 
     required: [
@@ -50,7 +51,6 @@
         "android.hardware.biometrics.fingerprint-V2.1-java",
         "android.hardware.oemlock-V1.0-java",
         "android.hardware.tetheroffload.control-V1.0-java",
-        "android.hardware.vibrator-V1.4-java",
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 81eb4b3..ce4cdc8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -146,6 +146,7 @@
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
@@ -2185,6 +2186,11 @@
      */
     @VisibleForTesting
     public void systemReady() {
+        // Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady
+        // before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be
+        // populated first to ensure that listening network request which is sent by
+        // MultipathPolicyTracker won't be added NET_CAPABILITY_FOREGROUND capability.
+        mPermissionMonitor.startMonitoring();
         mProxyTracker.loadGlobalProxy();
         registerNetdEventCallback();
         mTethering.systemReady();
@@ -2205,8 +2211,6 @@
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
-
-        mPermissionMonitor.startMonitoring();
     }
 
     /**
@@ -3050,7 +3054,8 @@
     }
 
     private void handleAsyncChannelHalfConnect(Message msg) {
-        AsyncChannel ac = (AsyncChannel) msg.obj;
+        ensureRunningOnConnectivityServiceThread();
+        final AsyncChannel ac = (AsyncChannel) msg.obj;
         if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
             if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                 if (VDBG) log("NetworkFactory connected");
@@ -3060,7 +3065,8 @@
                 // A network factory has connected.  Send it all current NetworkRequests.
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                     if (nri.request.isListen()) continue;
-                    NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+                    ensureRunningOnConnectivityServiceThread();
+                    NetworkAgentInfo nai = nri.mSatisfier;
                     final int score;
                     final int serial;
                     if (nai != null) {
@@ -3116,6 +3122,7 @@
     // ConnectivityService, free its interfaces and clean up.
     // Must be called on the Handler thread.
     private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+        ensureRunningOnConnectivityServiceThread();
         if (DBG) {
             log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
         }
@@ -3162,14 +3169,17 @@
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest request = nai.requestAt(i);
-            NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+            final NetworkRequestInfo nri = mNetworkRequests.get(request);
+            ensureRunningOnConnectivityServiceThread();
+            final NetworkAgentInfo currentNetwork = nri.mSatisfier;
             if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
-                clearNetworkForRequest(request.requestId);
+                nri.mSatisfier = null;
                 sendUpdatedScoreToFactories(request, null);
             }
         }
         nai.clearLingerState();
         if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+            mDefaultNetworkNai = null;
             updateDataActivityTracking(null /* newNetwork */, nai);
             notifyLockdownVpn(nai);
             ensureNetworkTransitionWakelock(nai.name());
@@ -3178,7 +3188,7 @@
         if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
             updateAllVpnsCapabilities();
         }
-        rematchAllNetworksAndRequests(null, 0);
+        rematchAllNetworksAndRequests();
         mLingerMonitor.noteDisconnect(nai);
         if (nai.created) {
             // Tell netd to clean up the configuration for this network
@@ -3253,6 +3263,7 @@
     }
 
     private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
+        ensureRunningOnConnectivityServiceThread();
         mNetworkRequests.put(nri.request, nri);
         mNetworkRequestInfoLogs.log("REGISTER " + nri);
         if (nri.request.isListen()) {
@@ -3263,8 +3274,8 @@
                 }
             }
         }
-        rematchAllNetworksAndRequests(null, 0);
-        if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
+        rematchAllNetworksAndRequests();
+        if (nri.request.isRequest() && nri.mSatisfier == null) {
             sendUpdatedScoreToFactories(nri.request, null);
         }
     }
@@ -3286,6 +3297,7 @@
     // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
     //   then it should be lingered.
     private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
+        ensureRunningOnConnectivityServiceThread();
         final int numRequests;
         switch (reason) {
             case TEARDOWN:
@@ -3310,6 +3322,7 @@
 
             // If this Network is already the highest scoring Network for a request, or if
             // there is hope for it to become one if it validated, then it is needed.
+            ensureRunningOnConnectivityServiceThread();
             if (nri.request.isRequest() && nai.satisfies(nri.request) &&
                     (nai.isSatisfyingRequest(nri.request.requestId) ||
                     // Note that this catches two important cases:
@@ -3319,8 +3332,8 @@
                     // 2. Unvalidated WiFi will not be reaped when validated cellular
                     //    is currently satisfying the request.  This is desirable when
                     //    WiFi ends up validating and out scoring cellular.
-                    getNetworkForRequest(nri.request.requestId).getCurrentScore() <
-                            nai.getCurrentScoreAsValidated())) {
+                    nri.mSatisfier.getCurrentScore()
+                            < nai.getCurrentScoreAsValidated())) {
                 return false;
             }
         }
@@ -3344,10 +3357,12 @@
     }
 
     private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+        ensureRunningOnConnectivityServiceThread();
         if (mNetworkRequests.get(nri.request) == null) {
             return;
         }
-        if (getNetworkForRequest(nri.request.requestId) != null) {
+        ensureRunningOnConnectivityServiceThread();
+        if (nri.mSatisfier != null) {
             return;
         }
         if (VDBG || (DBG && nri.request.isRequest())) {
@@ -3374,6 +3389,8 @@
     }
 
     private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
+        ensureRunningOnConnectivityServiceThread();
+
         nri.unlinkDeathRecipient();
         mNetworkRequests.remove(nri.request);
 
@@ -3393,7 +3410,8 @@
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         if (nri.request.isRequest()) {
             boolean wasKept = false;
-            NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
+            ensureRunningOnConnectivityServiceThread();
+            final NetworkAgentInfo nai = nri.mSatisfier;
             if (nai != null) {
                 boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
                 nai.removeRequest(nri.request.requestId);
@@ -3410,7 +3428,7 @@
                 } else {
                     wasKept = true;
                 }
-                clearNetworkForRequest(nri.request.requestId);
+                nri.mSatisfier = null;
                 if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
                     // Went from foreground to background.
                     updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -3499,13 +3517,12 @@
         }
 
         if (accept != nai.networkMisc.acceptUnvalidated) {
-            int oldScore = nai.getCurrentScore();
             nai.networkMisc.acceptUnvalidated = accept;
             // If network becomes partial connectivity and user already accepted to use this
             // network, we should respect the user's option and don't need to popup the
             // PARTIAL_CONNECTIVITY notification to user again.
             nai.networkMisc.acceptPartialConnectivity = accept;
-            rematchAllNetworksAndRequests(nai, oldScore);
+            rematchAllNetworksAndRequests();
             sendUpdatedScoreToFactories(nai);
         }
 
@@ -3574,9 +3591,8 @@
             return;
         }
         if (!nai.avoidUnvalidated) {
-            int oldScore = nai.getCurrentScore();
             nai.avoidUnvalidated = true;
-            rematchAllNetworksAndRequests(nai, oldScore);
+            rematchAllNetworksAndRequests();
             sendUpdatedScoreToFactories(nai);
         }
     }
@@ -3677,7 +3693,7 @@
 
 
     private void rematchForAvoidBadWifiUpdate() {
-        rematchAllNetworksAndRequests(null, 0);
+        rematchAllNetworksAndRequests();
         for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
             if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                 sendUpdatedScoreToFactories(nai);
@@ -5093,6 +5109,11 @@
      */
     private class NetworkRequestInfo implements IBinder.DeathRecipient {
         final NetworkRequest request;
+        // The network currently satisfying this request, or null if none. Must only be touched
+        // on the handler thread. This only makes sense for network requests and not for listens,
+        // as defined by NetworkRequest#isRequest(). For listens, this is always null.
+        @Nullable
+        NetworkAgentInfo mSatisfier;
         final PendingIntent mPendingIntent;
         boolean mPendingIntentSent;
         private final IBinder mBinder;
@@ -5479,16 +5500,6 @@
         if (DBG) log("unregisterNetworkFactory for " + nfi.name);
     }
 
-    /**
-     * NetworkAgentInfo supporting a request by requestId.
-     * These have already been vetted (their Capabilities satisfy the request)
-     * and the are the highest scored network available.
-     * the are keyed off the Requests requestId.
-     */
-    // NOTE: Accessed on multiple threads, must be synchronized on itself.
-    @GuardedBy("mNetworkForRequestId")
-    private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<>();
-
     // NOTE: Accessed on multiple threads, must be synchronized on itself.
     @GuardedBy("mNetworkForNetId")
     private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
@@ -5506,7 +5517,11 @@
     private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
 
     // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
+    @NonNull
     private final NetworkRequest mDefaultRequest;
+    // The NetworkAgentInfo currently satisfying the default request, if any.
+    @Nullable
+    private volatile NetworkAgentInfo mDefaultNetworkNai = null;
 
     // Request used to optionally keep mobile data active even when higher
     // priority networks like Wi-Fi are active.
@@ -5516,26 +5531,8 @@
     // priority networks like ethernet are active.
     private final NetworkRequest mDefaultWifiRequest;
 
-    private NetworkAgentInfo getNetworkForRequest(int requestId) {
-        synchronized (mNetworkForRequestId) {
-            return mNetworkForRequestId.get(requestId);
-        }
-    }
-
-    private void clearNetworkForRequest(int requestId) {
-        synchronized (mNetworkForRequestId) {
-            mNetworkForRequestId.remove(requestId);
-        }
-    }
-
-    private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
-        synchronized (mNetworkForRequestId) {
-            mNetworkForRequestId.put(requestId, nai);
-        }
-    }
-
     private NetworkAgentInfo getDefaultNetwork() {
-        return getNetworkForRequest(mDefaultRequest.requestId);
+        return mDefaultNetworkNai;
     }
 
     @Nullable
@@ -5968,7 +5965,7 @@
         } else {
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
-            rematchAllNetworksAndRequests(nai, oldScore);
+            rematchAllNetworksAndRequests();
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -6253,7 +6250,7 @@
         }
     }
 
-    private void makeDefault(NetworkAgentInfo newNetwork) {
+    private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
         if (DBG) log("Switching to new default network: " + newNetwork);
 
         try {
@@ -6262,6 +6259,7 @@
             loge("Exception setting default network :" + e);
         }
 
+        mDefaultNetworkNai = newNetwork;
         notifyLockdownVpn(newNetwork);
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
@@ -6296,6 +6294,41 @@
         }
     }
 
+    private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
+            @NonNull final NetworkAgentInfo newNetwork) {
+        final int score = newNetwork.getCurrentScore();
+        final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>();
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            // Process requests in the first pass and listens in the second pass. This allows us to
+            // change a network's capabilities depending on which requests it has. This is only
+            // correct if the change in capabilities doesn't affect whether the network satisfies
+            // requests or not, and doesn't affect the network's score.
+            if (nri.request.isListen()) continue;
+
+            final NetworkAgentInfo currentNetwork = nri.mSatisfier;
+            final boolean satisfies = newNetwork.satisfies(nri.request);
+            if (newNetwork == currentNetwork && satisfies) continue;
+
+            // check if it satisfies the NetworkCapabilities
+            if (VDBG) log("  checking if request is satisfied: " + nri.request);
+            if (satisfies) {
+                // next check if it's better than any current network we're using for
+                // this request
+                if (VDBG || DDBG) {
+                    log("currentScore = "
+                            + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0)
+                            + ", newScore = " + score);
+                }
+                if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
+                    reassignedRequests.put(nri, newNetwork);
+                }
+            } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+                reassignedRequests.put(nri, null);
+            }
+        }
+        return reassignedRequests;
+    }
+
     // Handles a network appearing or improving its score.
     //
     // - Evaluates all current NetworkRequests that can be
@@ -6309,10 +6342,6 @@
     // - Tears down newNetwork if it just became validated
     //   but turns out to be unneeded.
     //
-    // - If reapUnvalidatedNetworks==REAP, tears down unvalidated
-    //   networks that have no chance (i.e. even if validated)
-    //   of becoming the highest scoring network.
-    //
     // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
     // it does not remove NetworkRequests that other Networks could better satisfy.
     // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
@@ -6320,11 +6349,9 @@
     // as it performs better by a factor of the number of Networks.
     //
     // @param newNetwork is the network to be matched against NetworkRequests.
-    // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be
-    //               performed to tear down unvalidated networks that have no chance (i.e. even if
-    //               validated) of becoming the highest scoring network.
-    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,
-            ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {
+    // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
+    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+        ensureRunningOnConnectivityServiceThread();
         if (!newNetwork.everConnected) return;
         boolean keep = newNetwork.isVPN();
         boolean isNewDefault = false;
@@ -6335,74 +6362,54 @@
 
         if (VDBG || DDBG) log("rematching " + newNetwork.name());
 
-        // Find and migrate to this Network any NetworkRequests for
-        // which this network is now the best.
-        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<>();
-        ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+        final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
+                computeRequestReassignmentForNetwork(newNetwork);
+
         NetworkCapabilities nc = newNetwork.networkCapabilities;
         if (VDBG) log(" network has: " + nc);
-        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-            // Process requests in the first pass and listens in the second pass. This allows us to
-            // change a network's capabilities depending on which requests it has. This is only
-            // correct if the change in capabilities doesn't affect whether the network satisfies
-            // requests or not, and doesn't affect the network's score.
-            if (nri.request.isListen()) continue;
 
-            final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
-            final boolean satisfies = newNetwork.satisfies(nri.request);
-            if (newNetwork == currentNetwork && satisfies) {
-                if (VDBG) {
-                    log("Network " + newNetwork.name() + " was already satisfying" +
-                            " request " + nri.request.requestId + ". No change.");
+        // Find and migrate to this Network any NetworkRequests for
+        // which this network is now the best.
+        final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
+        final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
+        for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
+                reassignedRequests.entrySet()) {
+            final NetworkRequestInfo nri = entry.getKey();
+            final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
+            final NetworkAgentInfo newSatisfier = entry.getValue();
+            if (newSatisfier != null) {
+                if (VDBG) log("rematch for " + newSatisfier.name());
+                if (previousSatisfier != null) {
+                    if (VDBG || DDBG) {
+                        log("   accepting network in place of " + previousSatisfier.name());
+                    }
+                    previousSatisfier.removeRequest(nri.request.requestId);
+                    previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
+                    removedRequests.add(previousSatisfier);
+                } else {
+                    if (VDBG || DDBG) log("   accepting network in place of null");
                 }
+                newSatisfier.unlingerRequest(nri.request);
+                nri.mSatisfier = newSatisfier;
+                if (!newSatisfier.addRequest(nri.request)) {
+                    Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
+                }
+                addedRequests.add(nri);
                 keep = true;
-                continue;
-            }
-
-            // check if it satisfies the NetworkCapabilities
-            if (VDBG) log("  checking if request is satisfied: " + nri.request);
-            if (satisfies) {
-                // next check if it's better than any current network we're using for
-                // this request
-                if (VDBG || DDBG) {
-                    log("currentScore = " +
-                            (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
-                            ", newScore = " + score);
-                }
-                if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
-                    if (VDBG) log("rematch for " + newNetwork.name());
-                    if (currentNetwork != null) {
-                        if (VDBG || DDBG){
-                            log("   accepting network in place of " + currentNetwork.name());
-                        }
-                        currentNetwork.removeRequest(nri.request.requestId);
-                        currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
-                        affectedNetworks.add(currentNetwork);
-                    } else {
-                        if (VDBG || DDBG) log("   accepting network in place of null");
-                    }
-                    newNetwork.unlingerRequest(nri.request);
-                    setNetworkForRequest(nri.request.requestId, newNetwork);
-                    if (!newNetwork.addRequest(nri.request)) {
-                        Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
-                    }
-                    addedRequests.add(nri);
-                    keep = true;
-                    // Tell NetworkFactories about the new score, so they can stop
-                    // trying to connect if they know they cannot match it.
-                    // TODO - this could get expensive if we have a lot of requests for this
-                    // network.  Think about if there is a way to reduce this.  Push
-                    // netid->request mapping to each factory?
-                    sendUpdatedScoreToFactories(nri.request, newNetwork);
-                    if (isDefaultRequest(nri)) {
-                        isNewDefault = true;
-                        oldDefaultNetwork = currentNetwork;
-                        if (currentNetwork != null) {
-                            mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);
-                        }
+                // Tell NetworkFactories about the new score, so they can stop
+                // trying to connect if they know they cannot match it.
+                // TODO - this could get expensive if we have a lot of requests for this
+                // network.  Think about if there is a way to reduce this.  Push
+                // netid->request mapping to each factory?
+                sendUpdatedScoreToFactories(nri.request, newSatisfier);
+                if (isDefaultRequest(nri)) {
+                    isNewDefault = true;
+                    oldDefaultNetwork = previousSatisfier;
+                    if (previousSatisfier != null) {
+                        mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
                     }
                 }
-            } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
+            } else {
                 // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
                 // mark it as no longer satisfying "nri".  Because networks are processed by
                 // rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
@@ -6415,13 +6422,14 @@
                             " request " + nri.request.requestId);
                 }
                 newNetwork.removeRequest(nri.request.requestId);
-                if (currentNetwork == newNetwork) {
-                    clearNetworkForRequest(nri.request.requestId);
+                if (previousSatisfier == newNetwork) {
+                    nri.mSatisfier = null;
+                    if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
                     sendUpdatedScoreToFactories(nri.request, null);
                 } else {
                     Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
                             newNetwork.name() +
-                            " without updating mNetworkForRequestId or factories!");
+                            " without updating mSatisfier or factories!");
                 }
                 // TODO: Technically, sending CALLBACK_LOST here is
                 // incorrect if there is a replacement network currently
@@ -6433,6 +6441,7 @@
                 callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
             }
         }
+
         if (isNewDefault) {
             updateDataActivityTracking(newNetwork, oldDefaultNetwork);
             // Notify system services that this network is up.
@@ -6472,7 +6481,7 @@
 
         // Linger any networks that are no longer needed. This should be done after sending the
         // available callback for newNetwork.
-        for (NetworkAgentInfo nai : affectedNetworks) {
+        for (NetworkAgentInfo nai : removedRequests) {
             updateLingerState(nai, now);
         }
         // Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
@@ -6540,66 +6549,43 @@
                 mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
             }
         }
-        if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {
-            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                if (unneeded(nai, UnneededFor.TEARDOWN)) {
-                    if (nai.getLingerExpiry() > 0) {
-                        // This network has active linger timers and no requests, but is not
-                        // lingering. Linger it.
-                        //
-                        // One way (the only way?) this can happen if this network is unvalidated
-                        // and became unneeded due to another network improving its score to the
-                        // point where this network will no longer be able to satisfy any requests
-                        // even if it validates.
-                        updateLingerState(nai, now);
-                    } else {
-                        if (DBG) log("Reaping " + nai.name());
-                        teardownUnneededNetwork(nai);
-                    }
-                }
-            }
-        }
     }
 
     /**
      * Attempt to rematch all Networks with NetworkRequests.  This may result in Networks
      * being disconnected.
-     * @param changed If only one Network's score or capabilities have been modified since the last
-     *         time this function was called, pass this Network in this argument, otherwise pass
-     *         null.
-     * @param oldScore If only one Network has been changed but its NetworkCapabilities have not
-     *         changed, pass in the Network's score (from getCurrentScore()) prior to the change via
-     *         this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
-     *         {@code changed} is {@code null}. This is because NetworkCapabilities influence a
-     *         network's score.
      */
-    private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
-        // TODO: This may get slow.  The "changed" parameter is provided for future optimization
-        // to avoid the slowness.  It is not simply enough to process just "changed", for
-        // example in the case where "changed"'s score decreases and another network should begin
-        // satisfying a NetworkRequest that "changed" currently satisfies.
-
-        // Optimization: Only reprocess "changed" if its score improved.  This is safe because it
-        // can only add more NetworkRequests satisfied by "changed", and this is exactly what
-        // rematchNetworkAndRequests() handles.
+    private void rematchAllNetworksAndRequests() {
+        // TODO: This may be slow, and should be optimized. Unfortunately at this moment the
+        // processing is network-major instead of request-major (the code iterates through all
+        // networks, then for each it iterates for all requests), which is a problem for re-scoring
+        // requests. Once the code has switched to a request-major iteration style, this can
+        // be optimized to only do the processing needed.
         final long now = SystemClock.elapsedRealtime();
-        if (changed != null && oldScore < changed.getCurrentScore()) {
-            rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);
-        } else {
-            final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
-                    new NetworkAgentInfo[mNetworkAgentInfos.size()]);
-            // Rematch higher scoring networks first to prevent requests first matching a lower
-            // scoring network and then a higher scoring network, which could produce multiple
-            // callbacks and inadvertently unlinger networks.
-            Arrays.sort(nais);
-            for (NetworkAgentInfo nai : nais) {
-                rematchNetworkAndRequests(nai,
-                        // Only reap the last time through the loop.  Reaping before all rematching
-                        // is complete could incorrectly teardown a network that hasn't yet been
-                        // rematched.
-                        (nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP
-                                : ReapUnvalidatedNetworks.REAP,
-                        now);
+        final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
+                new NetworkAgentInfo[mNetworkAgentInfos.size()]);
+        // Rematch higher scoring networks first to prevent requests first matching a lower
+        // scoring network and then a higher scoring network, which could produce multiple
+        // callbacks and inadvertently unlinger networks.
+        Arrays.sort(nais);
+        for (NetworkAgentInfo nai : nais) {
+            rematchNetworkAndRequests(nai, now);
+        }
+        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            if (unneeded(nai, UnneededFor.TEARDOWN)) {
+                if (nai.getLingerExpiry() > 0) {
+                    // This network has active linger timers and no requests, but is not
+                    // lingering. Linger it.
+                    //
+                    // One way (the only way?) this can happen if this network is unvalidated
+                    // and became unneeded due to another network improving its score to the
+                    // point where this network will no longer be able to satisfy any requests
+                    // even if it validates.
+                    updateLingerState(nai, now);
+                } else {
+                    if (DBG) log("Reaping " + nai.name());
+                    teardownUnneededNetwork(nai);
+                }
             }
         }
     }
@@ -6698,8 +6684,7 @@
             }
 
             // Consider network even though it is not yet validated.
-            final long now = SystemClock.elapsedRealtime();
-            rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
+            rematchAllNetworksAndRequests();
 
             // This has to happen after matching the requests, because callbacks are just requests.
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
@@ -6720,7 +6705,7 @@
                 state == NetworkInfo.State.SUSPENDED)) {
             // going into or coming out of SUSPEND: re-score and notify
             if (networkAgent.getCurrentScore() != oldScore) {
-                rematchAllNetworksAndRequests(networkAgent, oldScore);
+                rematchAllNetworksAndRequests();
             }
             updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
                     networkAgent.networkCapabilities);
@@ -6734,19 +6719,9 @@
     }
 
     private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
-        int score = ns.getIntExtension(NetworkScore.LEGACY_SCORE);
-        if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + score);
-        if (score < 0) {
-            loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
-                    ").  Bumping score to min of 0");
-            score = 0;
-        }
-
-        final int oldScore = nai.getCurrentScore();
+        if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + ns);
         nai.setNetworkScore(ns);
-
-        rematchAllNetworksAndRequests(nai, oldScore);
-
+        rematchAllNetworksAndRequests();
         sendUpdatedScoreToFactories(nai);
     }
 
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 80d7ac9..9a7a4e7 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -60,12 +60,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.telephony.SmsApplication;
 import com.android.internal.util.DumpUtils;
 
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -908,17 +905,6 @@
             }
             writer.println("Current scorer: " + currentScorer);
 
-            sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
-                @Override
-                public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
-                    try {
-                        TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
-                    } catch (IOException | RemoteException e) {
-                        writer.println("Failed to dump score cache: " + e);
-                    }
-                }
-            }, getScoreCacheLists());
-
             synchronized (mServiceConnectionLock) {
                 if (mServiceConnection != null) {
                     mServiceConnection.dump(fd, writer, args);
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
deleted file mode 100644
index 997178e..0000000
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.IRecoverySystem;
-import android.os.IRecoverySystemProgressListener;
-import android.os.PowerManager;
-import android.os.RecoverySystem;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Slog;
-
-import libcore.io.IoUtils;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * The recovery system service is responsible for coordinating recovery related
- * functions on the device. It sets up (or clears) the bootloader control block
- * (BCB), which will be read by the bootloader and the recovery image. It also
- * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
- * /data partition so that it can be accessed under the recovery image.
- */
-public final class RecoverySystemService extends SystemService {
-    private static final String TAG = "RecoverySystemService";
-    private static final boolean DEBUG = false;
-
-    // The socket at /dev/socket/uncrypt to communicate with uncrypt.
-    private static final String UNCRYPT_SOCKET = "uncrypt";
-
-    // The init services that communicate with /system/bin/uncrypt.
-    private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
-    private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
-    private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
-
-    private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
-
-    private static final Object sRequestLock = new Object();
-
-    private Context mContext;
-
-    public RecoverySystemService(Context context) {
-        super(context);
-        mContext = context;
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.RECOVERY_SERVICE, new BinderService());
-    }
-
-    private final class BinderService extends IRecoverySystem.Stub {
-        @Override // Binder call
-        public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
-            if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
-
-            synchronized (sRequestLock) {
-                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
-                final boolean available = checkAndWaitForUncryptService();
-                if (!available) {
-                    Slog.e(TAG, "uncrypt service is unavailable.");
-                    return false;
-                }
-
-                // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
-                // uncrypt.
-                RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
-
-                try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
-                    uncryptFile.write(filename + "\n");
-                } catch (IOException e) {
-                    Slog.e(TAG, "IOException when writing \"" +
-                            RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
-                    return false;
-                }
-
-                // Trigger uncrypt via init.
-                SystemProperties.set("ctl.start", "uncrypt");
-
-                // Connect to the uncrypt service socket.
-                LocalSocket socket = connectService();
-                if (socket == null) {
-                    Slog.e(TAG, "Failed to connect to uncrypt socket");
-                    return false;
-                }
-
-                // Read the status from the socket.
-                DataInputStream dis = null;
-                DataOutputStream dos = null;
-                try {
-                    dis = new DataInputStream(socket.getInputStream());
-                    dos = new DataOutputStream(socket.getOutputStream());
-                    int lastStatus = Integer.MIN_VALUE;
-                    while (true) {
-                        int status = dis.readInt();
-                        // Avoid flooding the log with the same message.
-                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
-                            continue;
-                        }
-                        lastStatus = status;
-
-                        if (status >= 0 && status <= 100) {
-                            // Update status
-                            Slog.i(TAG, "uncrypt read status: " + status);
-                            if (listener != null) {
-                                try {
-                                    listener.onProgress(status);
-                                } catch (RemoteException ignored) {
-                                    Slog.w(TAG, "RemoteException when posting progress");
-                                }
-                            }
-                            if (status == 100) {
-                                Slog.i(TAG, "uncrypt successfully finished.");
-                                // Ack receipt of the final status code. uncrypt
-                                // waits for the ack so the socket won't be
-                                // destroyed before we receive the code.
-                                dos.writeInt(0);
-                                break;
-                            }
-                        } else {
-                            // Error in /system/bin/uncrypt.
-                            Slog.e(TAG, "uncrypt failed with status: " + status);
-                            // Ack receipt of the final status code. uncrypt waits
-                            // for the ack so the socket won't be destroyed before
-                            // we receive the code.
-                            dos.writeInt(0);
-                            return false;
-                        }
-                    }
-                } catch (IOException e) {
-                    Slog.e(TAG, "IOException when reading status: ", e);
-                    return false;
-                } finally {
-                    IoUtils.closeQuietly(dis);
-                    IoUtils.closeQuietly(dos);
-                    IoUtils.closeQuietly(socket);
-                }
-
-                return true;
-            }
-        }
-
-        @Override // Binder call
-        public boolean clearBcb() {
-            if (DEBUG) Slog.d(TAG, "clearBcb");
-            synchronized (sRequestLock) {
-                return setupOrClearBcb(false, null);
-            }
-        }
-
-        @Override // Binder call
-        public boolean setupBcb(String command) {
-            if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
-            synchronized (sRequestLock) {
-                return setupOrClearBcb(true, command);
-            }
-        }
-
-        @Override // Binder call
-        public void rebootRecoveryWithCommand(String command) {
-            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
-            synchronized (sRequestLock) {
-                if (!setupOrClearBcb(true, command)) {
-                    return;
-                }
-
-                // Having set up the BCB, go ahead and reboot.
-                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-                pm.reboot(PowerManager.REBOOT_RECOVERY);
-            }
-        }
-
-        /**
-         * Check if any of the init services is still running. If so, we cannot
-         * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
-         * it may break the socket communication since init creates / deletes
-         * the socket (/dev/socket/uncrypt) on service start / exit.
-         */
-        private boolean checkAndWaitForUncryptService() {
-            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
-                final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
-                final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
-                final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
-                final boolean busy = "running".equals(uncryptService) ||
-                        "running".equals(setupBcbService) || "running".equals(clearBcbService);
-                if (DEBUG) {
-                    Slog.i(TAG, "retry: " + retry + " busy: " + busy +
-                            " uncrypt: [" + uncryptService + "]" +
-                            " setupBcb: [" + setupBcbService + "]" +
-                            " clearBcb: [" + clearBcbService + "]");
-                }
-
-                if (!busy) {
-                    return true;
-                }
-
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                    Slog.w(TAG, "Interrupted:", e);
-                }
-            }
-
-            return false;
-        }
-
-        private LocalSocket connectService() {
-            LocalSocket socket = new LocalSocket();
-            boolean done = false;
-            // The uncrypt socket will be created by init upon receiving the
-            // service request. It may not be ready by this point. So we will
-            // keep retrying until success or reaching timeout.
-            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
-                try {
-                    socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
-                            LocalSocketAddress.Namespace.RESERVED));
-                    done = true;
-                    break;
-                } catch (IOException ignored) {
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException e) {
-                        Slog.w(TAG, "Interrupted:", e);
-                    }
-                }
-            }
-            if (!done) {
-                Slog.e(TAG, "Timed out connecting to uncrypt socket");
-                return null;
-            }
-            return socket;
-        }
-
-        private boolean setupOrClearBcb(boolean isSetup, String command) {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
-            final boolean available = checkAndWaitForUncryptService();
-            if (!available) {
-                Slog.e(TAG, "uncrypt service is unavailable.");
-                return false;
-            }
-
-            if (isSetup) {
-                SystemProperties.set("ctl.start", "setup-bcb");
-            } else {
-                SystemProperties.set("ctl.start", "clear-bcb");
-            }
-
-            // Connect to the uncrypt service socket.
-            LocalSocket socket = connectService();
-            if (socket == null) {
-                Slog.e(TAG, "Failed to connect to uncrypt socket");
-                return false;
-            }
-
-            DataInputStream dis = null;
-            DataOutputStream dos = null;
-            try {
-                dis = new DataInputStream(socket.getInputStream());
-                dos = new DataOutputStream(socket.getOutputStream());
-
-                // Send the BCB commands if it's to setup BCB.
-                if (isSetup) {
-                    byte[] cmdUtf8 = command.getBytes("UTF-8");
-                    dos.writeInt(cmdUtf8.length);
-                    dos.write(cmdUtf8, 0, cmdUtf8.length);
-                }
-
-                // Read the status from the socket.
-                int status = dis.readInt();
-
-                // Ack receipt of the status code. uncrypt waits for the ack so
-                // the socket won't be destroyed before we receive the code.
-                dos.writeInt(0);
-
-                if (status == 100) {
-                    Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
-                            " bcb successfully finished.");
-                } else {
-                    // Error in /system/bin/uncrypt.
-                    Slog.e(TAG, "uncrypt failed with status: " + status);
-                    return false;
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "IOException when communicating with uncrypt:", e);
-                return false;
-            } finally {
-                IoUtils.closeQuietly(dis);
-                IoUtils.closeQuietly(dos);
-                IoUtils.closeQuietly(socket);
-            }
-
-            return true;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9693585..d1bc6af 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2803,12 +2803,6 @@
         enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
 
         if (StorageManager.isFileEncryptedNativeOrEmulated()) {
-            // When a user has secure lock screen, require secret to actually unlock.
-            // This check is mostly in place for emulation mode.
-            if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
-                throw new IllegalStateException("Secret required to unlock secure user " + userId);
-            }
-
             try {
                 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
                         encodeBytes(secret));
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 30a3563..d1e4231 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.annotation.IntRange;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -41,6 +42,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -53,6 +55,7 @@
 import android.service.dreams.Sandman;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -66,6 +69,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
@@ -81,6 +87,7 @@
     private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     private int mNightMode = UiModeManager.MODE_NIGHT_NO;
 
+    private Map<Integer, String> mCarModePackagePriority = new HashMap<>();
     private boolean mCarModeEnabled = false;
     private boolean mCharging = false;
     private boolean mPowerSave = false;
@@ -338,15 +345,25 @@
 
     private final IUiModeManager.Stub mService = new IUiModeManager.Stub() {
         @Override
-        public void enableCarMode(int flags) {
+        public void enableCarMode(@UiModeManager.EnableCarMode int flags,
+                @IntRange(from = 0) int priority, String callingPackage) {
             if (isUiModeLocked()) {
                 Slog.e(TAG, "enableCarMode while UI mode is locked");
                 return;
             }
+
+            if (priority != UiModeManager.DEFAULT_PRIORITY
+                    && getContext().checkCallingOrSelfPermission(
+                    android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Enabling car mode with a priority requires "
+                        + "permission ENTER_CAR_MODE_PRIORITIZED");
+            }
+
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    setCarModeLocked(true, flags);
+                    setCarModeLocked(true, flags, priority, callingPackage);
                     if (mSystemReady) {
                         updateLocked(flags, 0);
                     }
@@ -356,16 +373,49 @@
             }
         }
 
+        /**
+         * This method is only kept around for the time being; the AIDL has an UnsupportedAppUsage
+         * tag which means this method is technically considered part of the greylist "API".
+         * @param flags
+         */
         @Override
-        public void disableCarMode(int flags) {
+        public void disableCarMode(@UiModeManager.DisableCarMode int flags) {
+            disableCarModeByCallingPackage(flags, null /* callingPackage */);
+        }
+
+        /**
+         * Handles requests to disable car mode.
+         * @param flags Disable car mode flags
+         * @param callingPackage
+         */
+        @Override
+        public void disableCarModeByCallingPackage(@UiModeManager.DisableCarMode int flags,
+                String callingPackage) {
             if (isUiModeLocked()) {
                 Slog.e(TAG, "disableCarMode while UI mode is locked");
                 return;
             }
+
+            // If the caller is the system, we will allow the DISABLE_CAR_MODE_ALL_PRIORITIES car
+            // mode flag to be specified; this is so that the user can disable car mode at all
+            // priorities using the persistent notification.
+            boolean isSystemCaller = Binder.getCallingUid() == Process.SYSTEM_UID;
+            final int carModeFlags =
+                    isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
+
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    setCarModeLocked(false, 0);
+                    // Determine if the caller has enabled car mode at a priority other than the
+                    // default one.  If they have, then attempt to disable at that priority.
+                    int priority = mCarModePackagePriority.entrySet()
+                            .stream()
+                            .filter(e -> e.getValue().equals(callingPackage))
+                            .findFirst()
+                            .map(Map.Entry::getKey)
+                            .orElse(UiModeManager.DEFAULT_PRIORITY);
+
+                    setCarModeLocked(false, carModeFlags, priority, callingPackage);
                     if (mSystemReady) {
                         updateLocked(0, flags);
                     }
@@ -471,19 +521,32 @@
         synchronized (mLock) {
             pw.println("Current UI Mode Service state:");
             pw.print("  mDockState="); pw.print(mDockState);
-                    pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+            pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+
             pw.print("  mNightMode="); pw.print(mNightMode); pw.print(" (");
-                    pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
-                    pw.print(" mNightModeLocked="); pw.print(mNightModeLocked);
-                    pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
-                    pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
-                    pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
-                    pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
+            pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+            pw.print(" mNightModeLocked="); pw.println(mNightModeLocked);
+
+            pw.print("  mCarModeEnabled="); pw.print(mCarModeEnabled);
+            pw.print(" (carModeApps=");
+            for (Map.Entry<Integer, String> entry : mCarModePackagePriority.entrySet()) {
+                pw.print(entry.getKey());
+                pw.print(":");
+                pw.print(entry.getValue());
+                pw.print(" ");
+            }
+            pw.println("");
+            pw.print(" mComputedNightMode="); pw.print(mComputedNightMode);
+            pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags);
+            pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch);
+
             pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
-                    pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
-                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+            pw.print(" mUiModeLocked="); pw.print(mUiModeLocked);
+            pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+
             pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
-                    pw.print(" mSystemReady="); pw.println(mSystemReady);
+            pw.print(" mSystemReady="); pw.println(mSystemReady);
+
             if (mTwilightManager != null) {
                 // We may not have a TwilightManager.
                 pw.print("  mTwilightService.getLastTwilightState()=");
@@ -506,12 +569,32 @@
         }
     }
 
-    void setCarModeLocked(boolean enabled, int flags) {
-        if (mCarModeEnabled != enabled) {
-            mCarModeEnabled = enabled;
+    /**
+     * Updates the global car mode state.
+     * The device is considered to be in car mode if there exists an app at any priority level which
+     * has entered car mode.
+     *
+     * @param enabled {@code true} if the caller wishes to enable car mode, {@code false} otherwise.
+     * @param flags Flags used when enabling/disabling car mode.
+     * @param priority The priority level for entering or exiting car mode; defaults to
+     *                 {@link UiModeManager#DEFAULT_PRIORITY} for callers using
+     *                 {@link UiModeManager#enableCarMode(int)}.  Callers using
+     *                 {@link UiModeManager#enableCarMode(int, int)} may specify a priority.
+     * @param packageName The package name of the app which initiated the request to enable or
+     *                    disable car mode.
+     */
+    void setCarModeLocked(boolean enabled, int flags, int priority, String packageName) {
+        if (enabled) {
+            enableCarMode(priority, packageName);
+        } else {
+            disableCarMode(flags, priority, packageName);
+        }
+        boolean isCarModeNowEnabled = isCarModeEnabled();
 
+        if (mCarModeEnabled != isCarModeNowEnabled) {
+            mCarModeEnabled = isCarModeNowEnabled;
             // When exiting car mode, restore night mode from settings
-            if (!mCarModeEnabled) {
+            if (!isCarModeNowEnabled) {
                 Context context = getContext();
                 updateNightModeFromSettings(context,
                         context.getResources(),
@@ -521,11 +604,102 @@
         mCarModeEnableFlags = flags;
     }
 
+    /**
+     * Handles disabling car mode.
+     * <p>
+     * Car mode can be disabled at a priority level if any of the following is true:
+     * 1. The priority being disabled is the {@link UiModeManager#DEFAULT_PRIORITY}.
+     * 2. The priority level is enabled and the caller is the app who originally enabled it.
+     * 3. The {@link UiModeManager#DISABLE_CAR_MODE_ALL_PRIORITIES} flag was specified, meaning all
+     *    car mode priorities are disabled.
+     *
+     * @param flags Car mode flags.
+     * @param priority The priority level at which to disable car mode.
+     * @param packageName The calling package which initiated the request.
+     */
+    private void disableCarMode(int flags, int priority, String packageName) {
+        boolean isDisableAll = (flags & UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES) != 0;
+        boolean isPriorityTracked = mCarModePackagePriority.keySet().contains(priority);
+        boolean isDefaultPriority = priority == UiModeManager.DEFAULT_PRIORITY;
+        boolean isChangeAllowed =
+                // Anyone can disable the default priority.
+                isDefaultPriority
+                // If priority was enabled, only enabling package can disable it.
+                || isPriorityTracked && mCarModePackagePriority.get(priority).equals(packageName)
+                // Disable all priorities flag can disable all regardless.
+                || isDisableAll;
+        if (isChangeAllowed) {
+            Slog.d(TAG, "disableCarMode: disabling, priority=" + priority
+                    + ", packageName=" + packageName);
+            if (isDisableAll) {
+                Set<Map.Entry<Integer, String>> entries =
+                        new ArraySet<>(mCarModePackagePriority.entrySet());
+                mCarModePackagePriority.clear();
+
+                for (Map.Entry<Integer, String> entry : entries) {
+                    notifyCarModeDisabled(entry.getKey(), entry.getValue());
+                }
+            } else {
+                mCarModePackagePriority.remove(priority);
+                notifyCarModeDisabled(priority, packageName);
+            }
+        }
+    }
+
+    /**
+     * Handles enabling car mode.
+     * <p>
+     * Car mode can be enabled at any priority if it has not already been enabled at that priority.
+     * The calling package is tracked for the first app which enters priority at the
+     * {@link UiModeManager#DEFAULT_PRIORITY}, though any app can disable it at that priority.
+     *
+     * @param priority The priority for enabling car mode.
+     * @param packageName The calling package which initiated the request.
+     */
+    private void enableCarMode(int priority, String packageName) {
+        boolean isPriorityTracked = mCarModePackagePriority.containsKey(priority);
+        boolean isPackagePresent = mCarModePackagePriority.containsValue(packageName);
+        if (!isPriorityTracked && !isPackagePresent) {
+            Slog.d(TAG, "enableCarMode: enabled at priority=" + priority + ", packageName="
+                    + packageName);
+            mCarModePackagePriority.put(priority, packageName);
+            notifyCarModeEnabled(priority, packageName);
+        } else {
+            Slog.d(TAG, "enableCarMode: car mode at priority " + priority + " already enabled.");
+        }
+
+    }
+
+    private void notifyCarModeEnabled(int priority, String packageName) {
+        Intent intent = new Intent(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
+        intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
+        intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
+        getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
+    }
+
+    private void notifyCarModeDisabled(int priority, String packageName) {
+        Intent intent = new Intent(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
+        intent.putExtra(UiModeManager.EXTRA_CALLING_PACKAGE, packageName);
+        intent.putExtra(UiModeManager.EXTRA_PRIORITY, priority);
+        getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+                android.Manifest.permission.HANDLE_CAR_MODE_CHANGES);
+    }
+
+    /**
+     * Determines if car mode is enabled at any priority level.
+     * @return {@code true} if car mode is enabled, {@code false} otherwise.
+     */
+    private boolean isCarModeEnabled() {
+        return mCarModePackagePriority.size() > 0;
+    }
+
     private void updateDockState(int newState) {
         synchronized (mLock) {
             if (newState != mDockState) {
                 mDockState = newState;
-                setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0);
+                setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0,
+                        UiModeManager.DEFAULT_PRIORITY, "" /* packageName */);
                 if (mSystemReady) {
                     updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
                 }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index d622fb4..0db8495 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -28,8 +28,8 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
+import android.hardware.vibrator.IVibrator;
 import android.hardware.vibrator.V1_0.EffectStrength;
-import android.hardware.vibrator.V1_4.Capabilities;
 import android.icu.text.DateFormat;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
@@ -1153,7 +1153,7 @@
                 long duration = vibratorPerformEffect(prebaked.getId(),
                         prebaked.getEffectStrength(), vib);
                 long timeout = duration;
-                if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) {
+                if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) {
                     timeout *= ASYNC_TIMEOUT_MULTIPLIER;
                 }
                 if (timeout > 0) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 83ad4e7..454941c 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -89,6 +89,7 @@
         "/system/bin/drmserver",
         "/system/bin/mediadrmserver",
         "/system/bin/mediaserver",
+        "/system/bin/netd",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
         "/system/bin/vold",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5af1480..d07ec48 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5276,11 +5276,14 @@
 
         // Inform checkpointing systems of success
         try {
+            // This line is needed to CTS test for the correct exception handling
+            // See b/138952436#comment36 for context
+            Slog.i(TAG, "About to commit checkpoint");
             IStorageManager storageManager = PackageHelper.getStorageManager();
             storageManager.commitChanges();
         } catch (Exception e) {
             PowerManager pm = (PowerManager)
-                     mInjector.getContext().getSystemService(Context.POWER_SERVICE);
+                     mContext.getSystemService(Context.POWER_SERVICE);
             pm.reboot("Checkpoint commit failed");
         }
 
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 709f3f8..ae5ad7e 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -126,6 +126,12 @@
     }
 
     @Override
+    public void clearOverridesForTest(String packageName) {
+        CompatConfig config = CompatConfig.get();
+        config.removePackageOverrides(packageName);
+    }
+
+    @Override
     public boolean clearOverride(long changeId, String packageName) {
         boolean existed = CompatConfig.get().removeOverride(changeId, packageName);
         killPackage(packageName);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index d13e675..bc83780 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -18,6 +18,7 @@
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
 import android.app.Notification;
@@ -89,14 +90,22 @@
         mNotificationTypeMap = new SparseIntArray();
     }
 
+    @VisibleForTesting
+    protected static int approximateTransportType(NetworkAgentInfo nai) {
+        return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
+    }
+
     // TODO: deal more gracefully with multi-transport networks.
     private static int getFirstTransportType(NetworkAgentInfo nai) {
+        // TODO: The range is wrong, the safer and correct way is to change the range from
+        // MIN_TRANSPORT to MAX_TRANSPORT.
         for (int i = 0; i < 64; i++) {
             if (nai.networkCapabilities.hasTransport(i)) return i;
         }
         return -1;
     }
 
+    // TODO: Remove @TransportType or change it to @Transport.
     private static String getTransportName(@TransportType int transportType) {
         Resources r = Resources.getSystem();
         String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
@@ -146,7 +155,7 @@
         final int transportType;
         final String name;
         if (nai != null) {
-            transportType = getFirstTransportType(nai);
+            transportType = approximateTransportType(nai);
             final String extraInfo = nai.networkInfo.getExtraInfo();
             name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
             // Only notify for Internet-capable networks.
@@ -175,7 +184,7 @@
                     tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
 
-        Resources r = Resources.getSystem();
+        Resources r = mContext.getResources();
         final CharSequence title;
         final CharSequence details;
         int icon = getIcon(transportType, notifyType);
@@ -239,7 +248,7 @@
             details = r.getString(R.string.captive_portal_logged_in_detailed);
         } else if (notifyType == NotificationType.NETWORK_SWITCH) {
             String fromTransport = getTransportName(transportType);
-            String toTransport = getTransportName(getFirstTransportType(switchToNai));
+            String toTransport = getTransportName(approximateTransportType(switchToNai));
             title = r.getString(R.string.network_switch_metered, toTransport);
             details = r.getString(R.string.network_switch_metered_detail, toTransport,
                     fromTransport);
@@ -340,8 +349,8 @@
     }
 
     public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
-        String fromTransport = getTransportName(getFirstTransportType(fromNai));
-        String toTransport = getTransportName(getFirstTransportType(toNai));
+        String fromTransport = getTransportName(approximateTransportType(fromNai));
+        String toTransport = getTransportName(approximateTransportType(toNai));
         String text = mContext.getResources().getString(
                 R.string.network_switch_metered_toast, fromTransport, toTransport);
         Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index f326f1d..ec48713 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -22,11 +22,11 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
+import dalvik.system.VMRuntime;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import dalvik.system.VMRuntime;
-
 /**
  * Provides various methods for obtaining and converting of instruction sets.
  *
@@ -113,12 +113,15 @@
         return allInstructionSets;
     }
 
-    public static String getPrimaryInstructionSet(ApplicationInfo info) {
-        if (info.primaryCpuAbi == null) {
+    /**
+     * Calculates the primary instruction set based on the computed Abis of a given package.
+     */
+    public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
+        if (abis.primary == null) {
             return getPreferredInstructionSet();
         }
 
-        return VMRuntime.getInstructionSet(info.primaryCpuAbi);
+        return VMRuntime.getInstructionSet(abis.primary);
     }
 
 }
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 62ea95b..f8c173f 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -32,6 +32,9 @@
 per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
 per-file UserManagerService.java = omakoto@google.com, yamasani@google.com
 per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
+per-file UserSystemPackageInstaller.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeDetails.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeFactory.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
 
 # security
 per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
new file mode 100644
index 0000000..6f46564
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.Set;
+
+@VisibleForTesting
+interface PackageAbiHelper {
+    /**
+     * Derive and get the location of native libraries for the given package,
+     * which varies depending on where and how the package was installed.
+     */
+    NativeLibraryPaths getNativeLibraryPaths(
+            PackageParser.Package pkg, File appLib32InstallDir);
+
+    /**
+     * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
+     * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
+     * validate any of this information, and instead assume that the system was built sensibly.
+     */
+    Abis getBundledAppAbis(PackageParser.Package pkg);
+
+    /**
+     * Derive the ABI of a non-system package located at {@code pkg}. This information
+     * is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
+     *
+     * If {@code extractLibs} is true, native libraries are extracted from the app if required.
+     */
+    Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            throws PackageManagerException;
+
+    /**
+     * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
+     * match. i.e, so that all packages can be run inside a single process if required.
+     *
+     * Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
+     * this function will either try and make the ABI for all packages in
+     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+     * variant is used when installing or updating a package that belongs to a shared user.
+     *
+     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+     * adds unnecessary complexity.
+     *
+     * @return the calculated primary abi that should be set for all non-specified packages
+     *         belonging to the shared user.
+     */
+    @Nullable
+    String getAdjustedAbiForSharedUser(
+            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+
+    /**
+     * The native library paths and related properties that should be set on a
+     * {@link android.content.pm.PackageParser.Package}.
+     */
+    final class NativeLibraryPaths {
+        public final String nativeLibraryRootDir;
+        public final boolean nativeLibraryRootRequiresIsa;
+        public final String nativeLibraryDir;
+        public final String secondaryNativeLibraryDir;
+
+        @VisibleForTesting
+        NativeLibraryPaths(String nativeLibraryRootDir,
+                boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
+                String secondaryNativeLibraryDir) {
+            this.nativeLibraryRootDir = nativeLibraryRootDir;
+            this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+            this.nativeLibraryDir = nativeLibraryDir;
+            this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        }
+
+        public void applyTo(PackageParser.Package pkg) {
+            pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+            pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+            pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
+            pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        }
+    }
+
+    /**
+     * The primary and secondary ABIs that should be set on a package and its package setting.
+     */
+    final class Abis {
+        public final String primary;
+        public final String secondary;
+
+        @VisibleForTesting
+        Abis(String primary, String secondary) {
+            this.primary = primary;
+            this.secondary = secondary;
+        }
+
+        Abis(PackageParser.Package pkg) {
+            this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+        }
+
+        public void applyTo(PackageParser.Package pkg) {
+            pkg.applicationInfo.primaryCpuAbi = primary;
+            pkg.applicationInfo.secondaryCpuAbi = secondary;
+        }
+        public void applyTo(PackageSetting pkgSetting) {
+            // pkgSetting might be null during rescan following uninstall of updates
+            // to a bundled app, so accommodate that possibility.  The settings in
+            // that case will be established later from the parsed package.
+            //
+            // If the settings aren't null, sync them up with what we've derived.
+            if (pkgSetting != null) {
+                pkgSetting.primaryCpuAbiString = primary;
+                pkgSetting.secondaryCpuAbiString = secondary;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
new file mode 100644
index 0000000..1d3d24c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+final class PackageAbiHelperImpl implements PackageAbiHelper {
+
+    private static String calculateBundledApkRoot(final String codePathString) {
+        final File codePath = new File(codePathString);
+        final File codeRoot;
+        if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+            codeRoot = Environment.getRootDirectory();
+        } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+            codeRoot = Environment.getOemDirectory();
+        } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+            codeRoot = Environment.getVendorDirectory();
+        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+            codeRoot = Environment.getOdmDirectory();
+        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+            codeRoot = Environment.getProductDirectory();
+        } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
+            codeRoot = Environment.getSystemExtDirectory();
+        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+            codeRoot = Environment.getOdmDirectory();
+        } else {
+            // Unrecognized code path; take its top real segment as the apk root:
+            // e.g. /something/app/blah.apk => /something
+            try {
+                File f = codePath.getCanonicalFile();
+                File parent = f.getParentFile();    // non-null because codePath is a file
+                File tmp;
+                while ((tmp = parent.getParentFile()) != null) {
+                    f = parent;
+                    parent = tmp;
+                }
+                codeRoot = f;
+                Slog.w(PackageManagerService.TAG, "Unrecognized code path "
+                        + codePath + " - using " + codeRoot);
+            } catch (IOException e) {
+                // Can't canonicalize the code path -- shenanigans?
+                Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+                return Environment.getRootDirectory().getPath();
+            }
+        }
+        return codeRoot.getPath();
+    }
+
+    // Utility method that returns the relative package path with respect
+    // to the installation directory. Like say for /data/data/com.test-1.apk
+    // string com.test-1 is returned.
+    private static String deriveCodePathName(String codePath) {
+        if (codePath == null) {
+            return null;
+        }
+        final File codeFile = new File(codePath);
+        final String name = codeFile.getName();
+        if (codeFile.isDirectory()) {
+            return name;
+        } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
+            final int lastDot = name.lastIndexOf('.');
+            return name.substring(0, lastDot);
+        } else {
+            Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
+            return null;
+        }
+    }
+
+    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+            PackageManagerException {
+        if (copyRet < 0) {
+            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
+                    && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+                throw new PackageManagerException(copyRet, message);
+            }
+        }
+    }
+
+    @Override
+    public NativeLibraryPaths getNativeLibraryPaths(
+            PackageParser.Package pkg, File appLib32InstallDir) {
+        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
+                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+                pkg.applicationInfo.isUpdatedSystemApp());
+    }
+
+    private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
+            final File appLib32InstallDir, final String codePath, final String sourceDir,
+            final boolean isSystemApp, final boolean isUpdatedSystemApp) {
+        final File codeFile = new File(codePath);
+        final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
+
+        final String nativeLibraryRootDir;
+        final boolean nativeLibraryRootRequiresIsa;
+        final String nativeLibraryDir;
+        final String secondaryNativeLibraryDir;
+
+        if (isApkFile(codeFile)) {
+            // Monolithic install
+            if (bundledApp) {
+                // If "/system/lib64/apkname" exists, assume that is the per-package
+                // native library directory to use; otherwise use "/system/lib/apkname".
+                final String apkRoot = calculateBundledApkRoot(sourceDir);
+                final boolean is64Bit = VMRuntime.is64BitInstructionSet(
+                        getPrimaryInstructionSet(abis));
+
+                // This is a bundled system app so choose the path based on the ABI.
+                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+                // is just the default path.
+                final String apkName = deriveCodePathName(codePath);
+                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+                nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
+                        apkName).getAbsolutePath();
+
+                if (abis.secondary != null) {
+                    final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
+                    secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
+                            secondaryLibDir, apkName).getAbsolutePath();
+                } else {
+                    secondaryNativeLibraryDir = null;
+                }
+            } else {
+                final String apkName = deriveCodePathName(codePath);
+                nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
+                        .getAbsolutePath();
+                secondaryNativeLibraryDir = null;
+            }
+
+            nativeLibraryRootRequiresIsa = false;
+            nativeLibraryDir = nativeLibraryRootDir;
+        } else {
+            // Cluster install
+            nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+            nativeLibraryRootRequiresIsa = true;
+
+            nativeLibraryDir = new File(nativeLibraryRootDir,
+                    getPrimaryInstructionSet(abis)).getAbsolutePath();
+
+            if (abis.secondary != null) {
+                secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
+                        VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
+            } else {
+                secondaryNativeLibraryDir = null;
+            }
+        }
+        return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
+                nativeLibraryDir, secondaryNativeLibraryDir);
+    }
+
+    @Override
+    public Abis getBundledAppAbis(PackageParser.Package pkg) {
+        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+        // If "/system/lib64/apkname" exists, assume that is the per-package
+        // native library directory to use; otherwise use "/system/lib/apkname".
+        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+        final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
+        return abis;
+    }
+
+    /**
+     * Deduces the ABI of a bundled app and sets the relevant fields on the
+     * parsed pkg object.
+     *
+     * @param apkRoot the root of the installed apk, something like {@code /system} or
+     *                {@code /oem} under which system libraries are installed.
+     * @param apkName the name of the installed package.
+     */
+    private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
+        final File codeFile = new File(pkg.codePath);
+
+        final boolean has64BitLibs;
+        final boolean has32BitLibs;
+
+        final String primaryCpuAbi;
+        final String secondaryCpuAbi;
+        if (isApkFile(codeFile)) {
+            // Monolithic install
+            has64BitLibs =
+                    (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+            has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
+        } else {
+            // Cluster install
+            final File rootDir = new File(codeFile, LIB_DIR_NAME);
+            if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
+                    && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
+                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
+                has64BitLibs = (new File(rootDir, isa)).exists();
+            } else {
+                has64BitLibs = false;
+            }
+            if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
+                    && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
+                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
+                has32BitLibs = (new File(rootDir, isa)).exists();
+            } else {
+                has32BitLibs = false;
+            }
+        }
+
+        if (has64BitLibs && !has32BitLibs) {
+            // The package has 64 bit libs, but not 32 bit libs. Its primary
+            // ABI should be 64 bit. We can safely assume here that the bundled
+            // native libraries correspond to the most preferred ABI in the list.
+
+            primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+            secondaryCpuAbi = null;
+        } else if (has32BitLibs && !has64BitLibs) {
+            // The package has 32 bit libs but not 64 bit libs. Its primary
+            // ABI should be 32 bit.
+
+            primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+            secondaryCpuAbi = null;
+        } else if (has32BitLibs && has64BitLibs) {
+            // The application has both 64 and 32 bit bundled libraries. We check
+            // here that the app declares multiArch support, and warn if it doesn't.
+            //
+            // We will be lenient here and record both ABIs. The primary will be the
+            // ABI that's higher on the list, i.e, a device that's configured to prefer
+            // 64 bit apps will see a 64 bit primary ABI,
+
+            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+                Slog.e(PackageManagerService.TAG,
+                        "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
+            }
+
+            if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
+                primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+                secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+            } else {
+                primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+                secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+            }
+        } else {
+            primaryCpuAbi = null;
+            secondaryCpuAbi = null;
+        }
+        return new Abis(primaryCpuAbi, secondaryCpuAbi);
+    }
+
+    @Override
+    public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
+            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            throws PackageManagerException {
+        // Give ourselves some initial paths; we'll come back for another
+        // pass once we've determined ABI below.
+        final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
+                PackageManagerService.sAppLib32InstallDir, pkg.codePath,
+                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
+                pkg.applicationInfo.isUpdatedSystemApp());
+
+        // We shouldn't attempt to extract libs from system app when it was not updated.
+        if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+            extractLibs = false;
+        }
+
+        final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
+        final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+
+        String primaryCpuAbi = null;
+        String secondaryCpuAbi = null;
+
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = NativeLibraryHelper.Handle.create(pkg);
+            // TODO(multiArch): This can be null for apps that didn't go through the
+            // usual installation process. We can calculate it again, like we
+            // do during install time.
+            //
+            // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+            // unnecessary.
+            final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+            // Null out the abis so that they can be recalculated.
+            primaryCpuAbi = null;
+            secondaryCpuAbi = null;
+            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+                // Warn if we've set an abiOverride for multi-lib packages..
+                // By definition, we need to copy both 32 and 64 bit libraries for
+                // such packages.
+                if (pkg.cpuAbiOverride != null
+                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+                    Slog.w(PackageManagerService.TAG,
+                            "Ignoring abiOverride for multi arch application.");
+                }
+
+                int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+                int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                        abi32 = NativeLibraryHelper.findSupportedAbi(
+                                handle, Build.SUPPORTED_32_BIT_ABIS);
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
+                // Shared library native code should be in the APK zip aligned
+                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Shared library native lib extraction not supported");
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+                    if (extractLibs) {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                useIsaSpecificSubdirs);
+                    } else {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                        abi64 = NativeLibraryHelper.findSupportedAbi(
+                                handle, Build.SUPPORTED_64_BIT_ABIS);
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
+                maybeThrowExceptionForMultiArchCopy(
+                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+                if (abi64 >= 0) {
+                    // Shared library native libs should be in the APK zip aligned
+                    if (extractLibs && pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library native lib extraction not supported");
+                    }
+                    primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+                }
+
+                if (abi32 >= 0) {
+                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+                    if (abi64 >= 0) {
+                        if (pkg.use32bitAbi) {
+                            secondaryCpuAbi = primaryCpuAbi;
+                            primaryCpuAbi = abi;
+                        } else {
+                            secondaryCpuAbi = abi;
+                        }
+                    } else {
+                        primaryCpuAbi = abi;
+                    }
+                }
+            } else {
+                String[] abiList = (cpuAbiOverride != null)
+                        ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
+
+                // Enable gross and lame hacks for apps that are built with old
+                // SDK tools. We must scan their APKs for renderscript bitcode and
+                // not launch them if it's present. Don't bother checking on devices
+                // that don't have 64 bit support.
+                boolean needsRenderScriptOverride = false;
+                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
+                        && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+                    abiList = Build.SUPPORTED_32_BIT_ABIS;
+                    needsRenderScriptOverride = true;
+                }
+
+                final int copyRet;
+                if (extractLibs) {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                } else {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+                    copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+                }
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Error unpackaging native libs for app, errorCode=" + copyRet);
+                }
+
+                if (copyRet >= 0) {
+                    // Shared libraries that have native libs must be multi-architecture
+                    if (pkg.isLibrary()) {
+                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                                "Shared library with native libs must be multiarch");
+                    }
+                    primaryCpuAbi = abiList[copyRet];
+                } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
+                        && cpuAbiOverride != null) {
+                    primaryCpuAbi = cpuAbiOverride;
+                } else if (needsRenderScriptOverride) {
+                    primaryCpuAbi = abiList[0];
+                }
+            }
+        } catch (IOException ioe) {
+            Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
+        } finally {
+            IoUtils.closeQuietly(handle);
+        }
+
+        // Now that we've calculated the ABIs and determined if it's an internal app,
+        // we will go ahead and populate the nativeLibraryPath.
+
+        final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
+        return new Pair<>(abis,
+                getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+                        pkg.codePath, pkg.applicationInfo.sourceDir,
+                        pkg.applicationInfo.isSystemApp(),
+                        pkg.applicationInfo.isUpdatedSystemApp()));
+    }
+
+    /**
+     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+     * i.e, so that all packages can be run inside a single process if required.
+     *
+     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+     * this function will either try and make the ABI for all packages in
+     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+     * variant is used when installing or updating a package that belongs to a shared user.
+     *
+     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+     * adds unnecessary complexity.
+     */
+    @Override
+    @Nullable
+    public String getAdjustedAbiForSharedUser(
+            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+        String requiredInstructionSet = null;
+        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+            requiredInstructionSet = VMRuntime.getInstructionSet(
+                    scannedPackage.applicationInfo.primaryCpuAbi);
+        }
+
+        PackageSetting requirer = null;
+        for (PackageSetting ps : packagesForUser) {
+            // If packagesForUser contains scannedPackage, we skip it. This will happen
+            // when scannedPackage is an update of an existing package. Without this check,
+            // we will never be able to change the ABI of any package belonging to a shared
+            // user, even if it's compatible with other packages.
+            if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+                continue;
+            }
+            if (ps.primaryCpuAbiString == null) {
+                continue;
+            }
+
+            final String instructionSet =
+                    VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
+            if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
+                // We have a mismatch between instruction sets (say arm vs arm64) warn about
+                // this but there's not much we can do.
+                String errorMessage = "Instruction set mismatch, "
+                        + ((requirer == null) ? "[caller]" : requirer)
+                        + " requires " + requiredInstructionSet + " whereas " + ps
+                        + " requires " + instructionSet;
+                Slog.w(PackageManagerService.TAG, errorMessage);
+            }
+
+            if (requiredInstructionSet == null) {
+                requiredInstructionSet = instructionSet;
+                requirer = ps;
+            }
+        }
+
+        if (requiredInstructionSet == null) {
+            return null;
+        }
+        final String adjustedAbi;
+        if (requirer != null) {
+            // requirer != null implies that either scannedPackage was null or that
+            // scannedPackage did not require an ABI, in which case we have to adjust
+            // scannedPackage to match the ABI of the set (which is the same as
+            // requirer's ABI)
+            adjustedAbi = requirer.primaryCpuAbiString;
+        } else {
+            // requirer == null implies that we're updating all ABIs in the set to
+            // match scannedPackage.
+            adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+        }
+        return adjustedAbi;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6f9a918..4eddb930 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -23,6 +23,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
+import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
 import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
@@ -1484,7 +1485,29 @@
                     "Too many files for apex install");
         }
 
-        mResolvedBaseFile = addedFiles[0];
+        try {
+            resolveStageDirLocked();
+        } catch (IOException e) {
+            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+                    "Failed to resolve stage location", e);
+        }
+
+        File addedFile = addedFiles[0]; // there is only one file
+
+        // Ensure file name has proper suffix
+        final String sourceName = addedFile.getName();
+        final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
+                ? sourceName
+                : sourceName + APEX_FILE_EXTENSION;
+        if (!FileUtils.isValidExtFilename(targetName)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Invalid filename: " + targetName);
+        }
+
+        final File targetFile = new File(mResolvedStageDir, targetName);
+        resolveAndStageFile(addedFile, targetFile);
+
+        mResolvedBaseFile = targetFile;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d7d7345..8d31b34 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -93,14 +93,12 @@
 
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -278,6 +276,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
@@ -433,7 +432,7 @@
     // user, but by default initialize to this.
     public static final boolean DEBUG_DEXOPT = false;
 
-    private static final boolean DEBUG_ABI_SELECTION = false;
+    static final boolean DEBUG_ABI_SELECTION = false;
     private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_APP_DATA = false;
 
@@ -663,7 +662,8 @@
     private static final File sAppInstallDir =
             new File(Environment.getDataDirectory(), "app");
     /** Directory where installed application's 32-bit native libraries are copied. */
-    private static final File sAppLib32InstallDir =
+    @VisibleForTesting
+    static final File sAppLib32InstallDir =
             new File(Environment.getDataDirectory(), "app-lib");
 
     // ----------------------------------------------------------------
@@ -754,6 +754,30 @@
 
     private final ApexManager mApexManager;
 
+    private final Injector mInjector;
+
+    /**
+     * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+     */
+    @VisibleForTesting
+    static class Injector {
+        private final UserManagerInternal mUserManager;
+        private final PackageAbiHelper mAbiHelper;
+
+        Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
+            mUserManager = userManager;
+            mAbiHelper = abiHelper;
+        }
+
+        public UserManagerInternal getUserManager() {
+            return mUserManager;
+        }
+
+        public PackageAbiHelper getAbiHelper() {
+            return mAbiHelper;
+        }
+    }
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2093,8 +2117,8 @@
             // survive long enough to benefit of background optimizations.
             for (int userId : firstUserIds) {
                 PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
-                // There's a race currently where some install events may interleave with an uninstall.
-                // This can lead to package info being null (b/36642664).
+                // There's a race currently where some install events may interleave with an
+                // uninstall. This can lead to package info being null (b/36642664).
                 if (info != null) {
                     mDexManager.notifyPackageInstalled(info, userId);
                 }
@@ -2164,6 +2188,7 @@
      * external/removable/unprotected storage.
      * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
      * corresponding {@link StorageEnum} storage type value if it is.
+     * corresponding {@link StorageEnum} storage type value if it is.
      */
     private static int getPackageExternalStorageType(VolumeInfo packageVolume,
             boolean packageIsExternal) {
@@ -2421,6 +2446,11 @@
                     mPermissionManager.getPermissionSettings(), mPackages);
         }
         }
+
+        // TODO(b/137961986): We should pass this via constructor, but would first need to create
+        // a packages lock that could also be passed in.
+        mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
+
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -3128,7 +3158,9 @@
                 // the rest of the commands above) because there's precious little we
                 // can do about it. A settings error is reported, though.
                 final List<String> changedAbiCodePath =
-                        adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+                        applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
+                        mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
+                                setting.packages, null /*scannedPackage*/));
                 if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
                     for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                         final String codePathString = changedAbiCodePath.get(i);
@@ -9397,7 +9429,8 @@
                             null /* originalPkgSetting */, null, parseFlags, scanFlags,
                             (pkg == mPlatformPackage), user);
                     applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-                    final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    final ScanResult scanResult =
+                            scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
                     if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
                         scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
                     }
@@ -10759,7 +10792,8 @@
     }
 
     /** The result of a package scan. */
-    private static class ScanResult {
+    @VisibleForTesting
+    static class ScanResult {
         /** The request that initiated the scan that produced this result. */
         public final ScanRequest request;
         /** Whether or not the package scan was successful */
@@ -10798,7 +10832,8 @@
     }
 
     /** A package to be scanned */
-    private static class ScanRequest {
+    @VisibleForTesting
+    static class ScanRequest {
         /** The parsed package */
         @NonNull public final PackageParser.Package pkg;
         /** The package this package replaces */
@@ -10991,7 +11026,7 @@
                     pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                     originalPkgSetting, realPkgName, parseFlags, scanFlags,
                     (pkg == mPlatformPackage), user);
-            return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+            return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
         }
     }
 
@@ -11216,20 +11251,70 @@
     }
 
     /**
+     * Applies the adjusted ABI calculated by
+     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+     * relevant packages and settings.
+     * @param sharedUserSetting The {@code SharedUserSetting} to adjust
+     * @param scannedPackage the package being scanned or null
+     * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
+     * @return the list of code paths that belong to packages that had their ABIs adjusted.
+     */
+    private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
+            PackageParser.Package scannedPackage, String adjustedAbi) {
+        if (scannedPackage != null)  {
+            scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+        }
+        List<String> changedAbiCodePath = null;
+        for (PackageSetting ps : sharedUserSetting.packages) {
+            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+                if (ps.primaryCpuAbiString != null) {
+                    continue;
+                }
+
+                ps.primaryCpuAbiString = adjustedAbi;
+                if (ps.pkg != null && ps.pkg.applicationInfo != null
+                        && !TextUtils.equals(
+                        adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
+                    ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+                    if (DEBUG_ABI_SELECTION) {
+                        Slog.i(TAG,
+                                "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+                                        + " (scannedPackage="
+                                        + (scannedPackage != null ? scannedPackage : "null")
+                                        + ")");
+                    }
+                    if (changedAbiCodePath == null) {
+                        changedAbiCodePath = new ArrayList<>();
+                    }
+                    changedAbiCodePath.add(ps.codePathString);
+                }
+            }
+        }
+        return changedAbiCodePath;
+    }
+
+
+    /**
      * Just scans the package without any side effects.
      * <p>Not entirely true at the moment. There is still one side effect -- this
      * method potentially modifies a live {@link PackageSetting} object representing
      * the package being scanned. This will be resolved in the future.
      *
+     * @param injector injector for acquiring dependencies
      * @param request Information about the package to be scanned
      * @param isUnderFactoryTest Whether or not the device is under factory test
      * @param currentTime The current time, in millis
      * @return The results of the scan
      */
     @GuardedBy("mInstallLock")
-    private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+    @VisibleForTesting
+    @NonNull
+    static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+            Injector injector,
             boolean isUnderFactoryTest, long currentTime)
-                    throws PackageManagerException {
+            throws PackageManagerException {
+        final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
+        final UserManagerInternal userManager = injector.getUserManager();
         final PackageParser.Package pkg = request.pkg;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -11335,7 +11420,7 @@
         if (!createNewPackage) {
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
             final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
-            setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+            setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
         }
         // TODO(patb): see if we can do away with disabled check here.
         if (disabledPkgSetting != null
@@ -11381,7 +11466,10 @@
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
+                        packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(pkg);
+                derivedAbi.second.applyTo(pkg);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
@@ -11389,8 +11477,13 @@
                 // structure. Try to detect abi based on directory structure.
                 if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
                         pkg.applicationInfo.primaryCpuAbi == null) {
-                    setBundledAppAbisAndRoots(pkg, pkgSetting);
-                    setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                    final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
+                            pkg);
+                    abis.applyTo(pkg);
+                    abis.applyTo(pkgSetting);
+                    final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                            packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                    nativeLibraryPaths.applyTo(pkg);
                 }
             } else {
                 // This is not a first boot or an upgrade, don't bother deriving the
@@ -11399,7 +11492,9 @@
                 pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
                 pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
 
-                setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                        packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                nativeLibraryPaths.applyTo(pkg);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -11420,7 +11515,9 @@
             // ABIs we've determined above. For non-moves, the path will be updated based on the
             // ABIs we determined during compilation, but the path will depend on the final
             // package path (after the rename away from the stage path).
-            setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+            final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
+                    packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
+            nativeLibraryPaths.applyTo(pkg);
         }
 
         // This is a special case for the "system" package, where the ABI is
@@ -11474,8 +11571,9 @@
             // We also do this *before* we perform dexopt on this package, so that
             // we can avoid redundant dexopts, and also to make sure we've got the
             // code and package path correct.
-            changedAbiCodePath =
-                    adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+                    packageAbiHelper.getAdjustedAbiForSharedUser(
+                            pkgSetting.sharedUser.packages, pkg));
         }
 
         if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -12325,264 +12423,6 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    /**
-     * Derive the ABI of a non-system package located at {@code scanFile}. This information
-     * is derived purely on the basis of the contents of {@code scanFile} and
-     * {@code cpuAbiOverride}.
-     *
-     * If {@code extractLibs} is true, native libraries are extracted from the app if required.
-     */
-    private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
-            boolean extractLibs)
-                    throws PackageManagerException {
-        // Give ourselves some initial paths; we'll come back for another
-        // pass once we've determined ABI below.
-        setNativeLibraryPaths(pkg, sAppLib32InstallDir);
-
-        // We shouldn't attempt to extract libs from system app when it was not updated.
-        if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
-            extractLibs = false;
-        }
-
-        final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
-        final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
-        NativeLibraryHelper.Handle handle = null;
-        try {
-            handle = NativeLibraryHelper.Handle.create(pkg);
-            // TODO(multiArch): This can be null for apps that didn't go through the
-            // usual installation process. We can calculate it again, like we
-            // do during install time.
-            //
-            // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
-            // unnecessary.
-            final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
-            // Null out the abis so that they can be recalculated.
-            pkg.applicationInfo.primaryCpuAbi = null;
-            pkg.applicationInfo.secondaryCpuAbi = null;
-            if (isMultiArch(pkg.applicationInfo)) {
-                // Warn if we've set an abiOverride for multi-lib packages..
-                // By definition, we need to copy both 32 and 64 bit libraries for
-                // such packages.
-                if (pkg.cpuAbiOverride != null
-                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
-                    Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
-                }
-
-                int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
-                int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
-                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-                    if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
-                                useIsaSpecificSubdirs);
-                    } else {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                        abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
-                    }
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-
-                // Shared library native code should be in the APK zip aligned
-                if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
-                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                            "Shared library native lib extraction not supported");
-                }
-
-                maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
-                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-                    if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
-                                useIsaSpecificSubdirs);
-                    } else {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                        abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
-                    }
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-
-                maybeThrowExceptionForMultiArchCopy(
-                        "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
-                if (abi64 >= 0) {
-                    // Shared library native libs should be in the APK zip aligned
-                    if (extractLibs && pkg.isLibrary()) {
-                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Shared library native lib extraction not supported");
-                    }
-                    pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
-                }
-
-                if (abi32 >= 0) {
-                    final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
-                    if (abi64 >= 0) {
-                        if (pkg.use32bitAbi) {
-                            pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
-                            pkg.applicationInfo.primaryCpuAbi = abi;
-                        } else {
-                            pkg.applicationInfo.secondaryCpuAbi = abi;
-                        }
-                    } else {
-                        pkg.applicationInfo.primaryCpuAbi = abi;
-                    }
-                }
-            } else {
-                String[] abiList = (cpuAbiOverride != null) ?
-                        new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
-                // Enable gross and lame hacks for apps that are built with old
-                // SDK tools. We must scan their APKs for renderscript bitcode and
-                // not launch them if it's present. Don't bother checking on devices
-                // that don't have 64 bit support.
-                boolean needsRenderScriptOverride = false;
-                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
-                        NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
-                    abiList = Build.SUPPORTED_32_BIT_ABIS;
-                    needsRenderScriptOverride = true;
-                }
-
-                final int copyRet;
-                if (extractLibs) {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
-                } else {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
-                    copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
-                }
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
-                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
-                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                            "Error unpackaging native libs for app, errorCode=" + copyRet);
-                }
-
-                if (copyRet >= 0) {
-                    // Shared libraries that have native libs must be multi-architecture
-                    if (pkg.isLibrary()) {
-                        throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Shared library with native libs must be multiarch");
-                    }
-                    pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
-                } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
-                    pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
-                } else if (needsRenderScriptOverride) {
-                    pkg.applicationInfo.primaryCpuAbi = abiList[0];
-                }
-            }
-        } catch (IOException ioe) {
-            Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
-        } finally {
-            IoUtils.closeQuietly(handle);
-        }
-
-        // Now that we've calculated the ABIs and determined if it's an internal app,
-        // we will go ahead and populate the nativeLibraryPath.
-        setNativeLibraryPaths(pkg, sAppLib32InstallDir);
-    }
-
-    /**
-     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
-     * i.e, so that all packages can be run inside a single process if required.
-     *
-     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
-     * this function will either try and make the ABI for all packages in {@code packagesForUser}
-     * match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
-     * the ABI selected for {@code packagesForUser}. This variant is used when installing or
-     * updating a package that belongs to a shared user.
-     *
-     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
-     * adds unnecessary complexity.
-     */
-    private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
-        List<String> changedAbiCodePath = null;
-        String requiredInstructionSet = null;
-        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
-            requiredInstructionSet = VMRuntime.getInstructionSet(
-                     scannedPackage.applicationInfo.primaryCpuAbi);
-        }
-
-        PackageSetting requirer = null;
-        for (PackageSetting ps : packagesForUser) {
-            // If packagesForUser contains scannedPackage, we skip it. This will happen
-            // when scannedPackage is an update of an existing package. Without this check,
-            // we will never be able to change the ABI of any package belonging to a shared
-            // user, even if it's compatible with other packages.
-            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
-                if (ps.primaryCpuAbiString == null) {
-                    continue;
-                }
-
-                final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
-                if (requiredInstructionSet != null && !instructionSet.equals(requiredInstructionSet)) {
-                    // We have a mismatch between instruction sets (say arm vs arm64) warn about
-                    // this but there's not much we can do.
-                    String errorMessage = "Instruction set mismatch, "
-                            + ((requirer == null) ? "[caller]" : requirer)
-                            + " requires " + requiredInstructionSet + " whereas " + ps
-                            + " requires " + instructionSet;
-                    Slog.w(TAG, errorMessage);
-                }
-
-                if (requiredInstructionSet == null) {
-                    requiredInstructionSet = instructionSet;
-                    requirer = ps;
-                }
-            }
-        }
-
-        if (requiredInstructionSet != null) {
-            String adjustedAbi;
-            if (requirer != null) {
-                // requirer != null implies that either scannedPackage was null or that scannedPackage
-                // did not require an ABI, in which case we have to adjust scannedPackage to match
-                // the ABI of the set (which is the same as requirer's ABI)
-                adjustedAbi = requirer.primaryCpuAbiString;
-                if (scannedPackage != null) {
-                    scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
-                }
-            } else {
-                // requirer == null implies that we're updating all ABIs in the set to
-                // match scannedPackage.
-                adjustedAbi =  scannedPackage.applicationInfo.primaryCpuAbi;
-            }
-
-            for (PackageSetting ps : packagesForUser) {
-                if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
-                    if (ps.primaryCpuAbiString != null) {
-                        continue;
-                    }
-
-                    ps.primaryCpuAbiString = adjustedAbi;
-                    if (ps.pkg != null && ps.pkg.applicationInfo != null &&
-                            !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
-                        ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
-                        if (DEBUG_ABI_SELECTION) {
-                            Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
-                                    + " (requirer="
-                                    + (requirer != null ? requirer.pkg : "null")
-                                    + ", scannedPackage="
-                                    + (scannedPackage != null ? scannedPackage : "null")
-                                    + ")");
-                        }
-                        if (changedAbiCodePath == null) {
-                            changedAbiCodePath = new ArrayList<>();
-                        }
-                        changedAbiCodePath.add(ps.codePathString);
-                    }
-                }
-            }
-        }
-        return changedAbiCodePath;
-    }
-
     private void setUpCustomResolverActivity(PackageParser.Package pkg) {
         synchronized (mPackages) {
             mResolverReplaced = true;
@@ -12634,207 +12474,6 @@
                 | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
     }
 
-    private static String calculateBundledApkRoot(final String codePathString) {
-        final File codePath = new File(codePathString);
-        final File codeRoot;
-        if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
-            codeRoot = Environment.getRootDirectory();
-        } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
-            codeRoot = Environment.getOemDirectory();
-        } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
-            codeRoot = Environment.getVendorDirectory();
-        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
-            codeRoot = Environment.getOdmDirectory();
-        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
-            codeRoot = Environment.getProductDirectory();
-        } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
-            codeRoot = Environment.getSystemExtDirectory();
-        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
-            codeRoot = Environment.getOdmDirectory();
-        } else {
-            // Unrecognized code path; take its top real segment as the apk root:
-            // e.g. /something/app/blah.apk => /something
-            try {
-                File f = codePath.getCanonicalFile();
-                File parent = f.getParentFile();    // non-null because codePath is a file
-                File tmp;
-                while ((tmp = parent.getParentFile()) != null) {
-                    f = parent;
-                    parent = tmp;
-                }
-                codeRoot = f;
-                Slog.w(TAG, "Unrecognized code path "
-                        + codePath + " - using " + codeRoot);
-            } catch (IOException e) {
-                // Can't canonicalize the code path -- shenanigans?
-                Slog.w(TAG, "Can't canonicalize code path " + codePath);
-                return Environment.getRootDirectory().getPath();
-            }
-        }
-        return codeRoot.getPath();
-    }
-
-    /**
-     * Derive and set the location of native libraries for the given package,
-     * which varies depending on where and how the package was installed.
-     */
-    private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
-        final ApplicationInfo info = pkg.applicationInfo;
-        final String codePath = pkg.codePath;
-        final File codeFile = new File(codePath);
-        final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
-
-        info.nativeLibraryRootDir = null;
-        info.nativeLibraryRootRequiresIsa = false;
-        info.nativeLibraryDir = null;
-        info.secondaryNativeLibraryDir = null;
-
-        if (isApkFile(codeFile)) {
-            // Monolithic install
-            if (bundledApp) {
-                // If "/system/lib64/apkname" exists, assume that is the per-package
-                // native library directory to use; otherwise use "/system/lib/apkname".
-                final String apkRoot = calculateBundledApkRoot(info.sourceDir);
-                final boolean is64Bit = VMRuntime.is64BitInstructionSet(
-                        getPrimaryInstructionSet(info));
-
-                // This is a bundled system app so choose the path based on the ABI.
-                // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
-                // is just the default path.
-                final String apkName = deriveCodePathName(codePath);
-                final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
-                info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
-                        apkName).getAbsolutePath();
-
-                if (info.secondaryCpuAbi != null) {
-                    final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
-                    info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
-                            secondaryLibDir, apkName).getAbsolutePath();
-                }
-            } else {
-                final String apkName = deriveCodePathName(codePath);
-                info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
-                        .getAbsolutePath();
-            }
-
-            info.nativeLibraryRootRequiresIsa = false;
-            info.nativeLibraryDir = info.nativeLibraryRootDir;
-        } else {
-            // Cluster install
-            info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
-            info.nativeLibraryRootRequiresIsa = true;
-
-            info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
-                    getPrimaryInstructionSet(info)).getAbsolutePath();
-
-            if (info.secondaryCpuAbi != null) {
-                info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
-            }
-        }
-    }
-
-    /**
-     * Calculate the abis and roots for a bundled app. These can uniquely
-     * be determined from the contents of the system partition, i.e whether
-     * it contains 64 or 32 bit shared libraries etc. We do not validate any
-     * of this information, and instead assume that the system was built
-     * sensibly.
-     */
-    private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
-                                           PackageSetting pkgSetting) {
-        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
-        // If "/system/lib64/apkname" exists, assume that is the per-package
-        // native library directory to use; otherwise use "/system/lib/apkname".
-        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
-        setBundledAppAbi(pkg, apkRoot, apkName);
-        // pkgSetting might be null during rescan following uninstall of updates
-        // to a bundled app, so accommodate that possibility.  The settings in
-        // that case will be established later from the parsed package.
-        //
-        // If the settings aren't null, sync them up with what we've just derived.
-        // note that apkRoot isn't stored in the package settings.
-        if (pkgSetting != null) {
-            pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-            pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
-        }
-    }
-
-    /**
-     * Deduces the ABI of a bundled app and sets the relevant fields on the
-     * parsed pkg object.
-     *
-     * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
-     *        under which system libraries are installed.
-     * @param apkName the name of the installed package.
-     */
-    private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
-        final File codeFile = new File(pkg.codePath);
-
-        final boolean has64BitLibs;
-        final boolean has32BitLibs;
-        if (isApkFile(codeFile)) {
-            // Monolithic install
-            has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
-            has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
-        } else {
-            // Cluster install
-            final File rootDir = new File(codeFile, LIB_DIR_NAME);
-            if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
-                    && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
-                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
-                has64BitLibs = (new File(rootDir, isa)).exists();
-            } else {
-                has64BitLibs = false;
-            }
-            if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
-                    && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
-                final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
-                has32BitLibs = (new File(rootDir, isa)).exists();
-            } else {
-                has32BitLibs = false;
-            }
-        }
-
-        if (has64BitLibs && !has32BitLibs) {
-            // The package has 64 bit libs, but not 32 bit libs. Its primary
-            // ABI should be 64 bit. We can safely assume here that the bundled
-            // native libraries correspond to the most preferred ABI in the list.
-
-            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        } else if (has32BitLibs && !has64BitLibs) {
-            // The package has 32 bit libs but not 64 bit libs. Its primary
-            // ABI should be 32 bit.
-
-            pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        } else if (has32BitLibs && has64BitLibs) {
-            // The application has both 64 and 32 bit bundled libraries. We check
-            // here that the app declares multiArch support, and warn if it doesn't.
-            //
-            // We will be lenient here and record both ABIs. The primary will be the
-            // ABI that's higher on the list, i.e, a device that's configured to prefer
-            // 64 bit apps will see a 64 bit primary ABI,
-
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
-                Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
-            }
-
-            if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
-                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-            } else {
-                pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
-                pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
-            }
-        } else {
-            pkg.applicationInfo.primaryCpuAbi = null;
-            pkg.applicationInfo.secondaryCpuAbi = null;
-        }
-    }
-
     private void killApplication(String pkgName, int appId, String reason) {
         killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
     }
@@ -13556,7 +13195,8 @@
                     // upgrade app from instant to full; we don't allow app downgrade
                     installed = true;
                 }
-                setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+                setInstantAppForUser(
+                        getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
             }
 
             if (installed) {
@@ -13604,8 +13244,8 @@
         }
     }
 
-    static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
-            boolean instantApp, boolean fullApp) {
+    static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+            int userId, boolean instantApp, boolean fullApp) {
         // no state specified; do nothing
         if (!instantApp && !fullApp) {
             return;
@@ -13617,7 +13257,7 @@
                 pkgSetting.setInstantApp(false /*instantApp*/, userId);
             }
         } else {
-            for (int currentUserId : sUserManager.getUserIds()) {
+            for (int currentUserId : userManager.getUserIds()) {
                 if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
                     pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
                 } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -15452,17 +15092,6 @@
                             TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
                     mPendingEnableRollback.append(enableRollbackToken, this);
 
-                    final int[] installedUsers;
-                    synchronized (mPackages) {
-                        PackageSetting ps = mSettings.getPackageLPr(pkgLite.packageName);
-                        if (ps != null) {
-                            installedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(),
-                                    true);
-                        } else {
-                            installedUsers = new int[0];
-                        }
-                    }
-
                     Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
                     enableRollbackIntent.putExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
@@ -15471,9 +15100,6 @@
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
                             installFlags);
                     enableRollbackIntent.putExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
-                            installedUsers);
-                    enableRollbackIntent.putExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
                             getRollbackUser().getIdentifier());
                     enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
@@ -15891,16 +15517,6 @@
         }
     }
 
-    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
-            PackageManagerException {
-        if (copyRet < 0) {
-            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
-                    copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
-                throw new PackageManagerException(copyRet, message);
-            }
-        }
-    }
-
     /**
      * Logic to handle movement of existing installed applications.
      */
@@ -16027,26 +15643,6 @@
         return result;
     }
 
-    // Utility method that returns the relative package path with respect
-    // to the installation directory. Like say for /data/data/com.test-1.apk
-    // string com.test-1 is returned.
-    static String deriveCodePathName(String codePath) {
-        if (codePath == null) {
-            return null;
-        }
-        final File codeFile = new File(codePath);
-        final String name = codeFile.getName();
-        if (codeFile.isDirectory()) {
-            return name;
-        } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
-            final int lastDot = name.lastIndexOf('.');
-            return name.substring(0, lastDot);
-        } else {
-            Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
-            return null;
-        }
-    }
-
     static class PackageInstalledInfo {
         String name;
         int uid;
@@ -16979,7 +16575,8 @@
                 final PrepareResult prepareResult;
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
-                    prepareResult = preparePackageLI(request.args, request.installResult);
+                    prepareResult =
+                            preparePackageLI(request.args, request.installResult);
                 } catch (PrepareFailure prepareFailure) {
                     request.installResult.setError(prepareFailure.error,
                             prepareFailure.getMessage());
@@ -17639,7 +17236,11 @@
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                         args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
+                                pkg, abiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(pkg);
+                derivedAbi.second.applyTo(pkg);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -18168,10 +17769,6 @@
         }
     }
 
-    private static boolean isMultiArch(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
-    }
-
     private static boolean isExternal(PackageParser.Package pkg) {
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
@@ -18180,7 +17777,7 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    private static boolean isSystemApp(PackageParser.Package pkg) {
+    static boolean isSystemApp(PackageParser.Package pkg) {
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
@@ -24520,6 +24117,12 @@
         public List<ResolveInfo> queryIntentActivities(
                 Intent intent, int flags, int filterCallingUid, int userId) {
             final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+            return queryIntentActivities(intent, resolvedType, flags, filterCallingUid, userId);
+        }
+
+        @Override
+        public List<ResolveInfo> queryIntentActivities(
+                Intent intent, String resolvedType, int flags, int filterCallingUid, int userId) {
             return PackageManagerService.this
                     .queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid,
                             userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 58f262c..029673f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -270,7 +270,8 @@
         updateAvailable = orig.updateAvailable;
     }
 
-    private PackageUserState modifyUserState(int userId) {
+    @VisibleForTesting
+    PackageUserState modifyUserState(int userId) {
         PackageUserState state = mUserState.get(userId);
         if (state == null) {
             state = new PackageUserState();
@@ -463,6 +464,18 @@
         state.harmfulAppWarning = harmfulAppWarning;
     }
 
+    void setUserState(int userId, PackageUserState otherState) {
+        setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
+                otherState.stopped, otherState.notLaunched, otherState.hidden,
+                otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
+                otherState.dialogInfo, otherState.suspendedAppExtras,
+                otherState.suspendedLauncherExtras, otherState.instantApp,
+                otherState.virtualPreload, otherState.lastDisableAppCaller,
+                otherState.enabledComponents, otherState.disabledComponents,
+                otherState.domainVerificationStatus, otherState.appLinkGeneration,
+                otherState.installReason, otherState.harmfulAppWarning);
+    }
+
     ArraySet<String> getEnabledComponents(int userId) {
         return readUserState(userId).enabledComponents;
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3bc2236..4ecfbfe 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3337,7 +3337,8 @@
             int flags, ComponentName cn, String scheme, PatternMatcher ssp,
             IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
         final List<ResolveInfo> ri =
-                pmInternal.queryIntentActivities(intent, flags, Binder.getCallingUid(), 0);
+                pmInternal.queryIntentActivities(
+                        intent, intent.getType(), flags, Binder.getCallingUid(), 0);
         if (PackageManagerService.DEBUG_PREFERRED) {
             Log.d(TAG, "Queried " + intent + " results: " + ri);
         }
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 15dc6ae..0101366 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,20 @@
     },
     {
       "name": "CtsCompilationTestCases"
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ],
   "imports": [
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
new file mode 100644
index 0000000..fe18fbf
--- /dev/null
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.IRecoverySystem;
+import android.os.IRecoverySystemProgressListener;
+import android.os.PowerManager;
+import android.os.RecoverySystem;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * The recovery system service is responsible for coordinating recovery related
+ * functions on the device. It sets up (or clears) the bootloader control block
+ * (BCB), which will be read by the bootloader and the recovery image. It also
+ * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
+ * /data partition so that it can be accessed under the recovery image.
+ */
+public class RecoverySystemService extends IRecoverySystem.Stub {
+    private static final String TAG = "RecoverySystemService";
+    private static final boolean DEBUG = false;
+
+    // The socket at /dev/socket/uncrypt to communicate with uncrypt.
+    private static final String UNCRYPT_SOCKET = "uncrypt";
+
+    // The init services that communicate with /system/bin/uncrypt.
+    @VisibleForTesting
+    static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+    @VisibleForTesting
+    static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+    @VisibleForTesting
+    static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+
+    private static final Object sRequestLock = new Object();
+
+    private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+
+    private final Injector mInjector;
+    private final Context mContext;
+
+    static class Injector {
+        protected final Context mContext;
+
+        Injector(Context context) {
+            mContext = context;
+        }
+
+        public Context getContext() {
+            return mContext;
+        }
+
+        public PowerManager getPowerManager() {
+            return (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        }
+
+        public String systemPropertiesGet(String key) {
+            return SystemProperties.get(key);
+        }
+
+        public void systemPropertiesSet(String key, String value) {
+            SystemProperties.set(key, value);
+        }
+
+        public boolean uncryptPackageFileDelete() {
+            return RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+        }
+
+        public String getUncryptPackageFileName() {
+            return RecoverySystem.UNCRYPT_PACKAGE_FILE.getName();
+        }
+
+        public FileWriter getUncryptPackageFileWriter() throws IOException {
+            return new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE);
+        }
+
+        public UncryptSocket connectService() {
+            UncryptSocket socket = new UncryptSocket();
+            if (!socket.connectService()) {
+                socket.close();
+                return null;
+            }
+            return socket;
+        }
+
+        public void threadSleep(long millis) throws InterruptedException {
+            Thread.sleep(millis);
+        }
+    }
+
+    /**
+     * Handles the lifecycle events for the RecoverySystemService.
+     */
+    public static final class Lifecycle extends SystemService {
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            RecoverySystemService recoverySystemService = new RecoverySystemService(getContext());
+            publishBinderService(Context.RECOVERY_SERVICE, recoverySystemService);
+        }
+    }
+
+    private RecoverySystemService(Context context) {
+        this(new Injector(context));
+    }
+
+    @VisibleForTesting
+    RecoverySystemService(Injector injector) {
+        mInjector = injector;
+        mContext = injector.getContext();
+    }
+
+    @Override // Binder call
+    public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
+        if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
+
+        synchronized (sRequestLock) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+            if (!checkAndWaitForUncryptService()) {
+                Slog.e(TAG, "uncrypt service is unavailable.");
+                return false;
+            }
+
+            // Write the filename into uncrypt package file to be read by
+            // uncrypt.
+            mInjector.uncryptPackageFileDelete();
+
+            try (FileWriter uncryptFile = mInjector.getUncryptPackageFileWriter()) {
+                uncryptFile.write(filename + "\n");
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when writing \""
+                        + mInjector.getUncryptPackageFileName() + "\":", e);
+                return false;
+            }
+
+            // Trigger uncrypt via init.
+            mInjector.systemPropertiesSet("ctl.start", "uncrypt");
+
+            // Connect to the uncrypt service socket.
+            UncryptSocket socket = mInjector.connectService();
+            if (socket == null) {
+                Slog.e(TAG, "Failed to connect to uncrypt socket");
+                return false;
+            }
+
+            // Read the status from the socket.
+            try {
+                int lastStatus = Integer.MIN_VALUE;
+                while (true) {
+                    int status = socket.getPercentageUncrypted();
+                    // Avoid flooding the log with the same message.
+                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+                        continue;
+                    }
+                    lastStatus = status;
+
+                    if (status >= 0 && status <= 100) {
+                        // Update status
+                        Slog.i(TAG, "uncrypt read status: " + status);
+                        if (listener != null) {
+                            try {
+                                listener.onProgress(status);
+                            } catch (RemoteException ignored) {
+                                Slog.w(TAG, "RemoteException when posting progress");
+                            }
+                        }
+                        if (status == 100) {
+                            Slog.i(TAG, "uncrypt successfully finished.");
+                            // Ack receipt of the final status code. uncrypt
+                            // waits for the ack so the socket won't be
+                            // destroyed before we receive the code.
+                            socket.sendAck();
+                            break;
+                        }
+                    } else {
+                        // Error in /system/bin/uncrypt.
+                        Slog.e(TAG, "uncrypt failed with status: " + status);
+                        // Ack receipt of the final status code. uncrypt waits
+                        // for the ack so the socket won't be destroyed before
+                        // we receive the code.
+                        socket.sendAck();
+                        return false;
+                    }
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when reading status: ", e);
+                return false;
+            } finally {
+                socket.close();
+            }
+
+            return true;
+        }
+    }
+
+    @Override // Binder call
+    public boolean clearBcb() {
+        if (DEBUG) Slog.d(TAG, "clearBcb");
+        synchronized (sRequestLock) {
+            return setupOrClearBcb(false, null);
+        }
+    }
+
+    @Override // Binder call
+    public boolean setupBcb(String command) {
+        if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
+        synchronized (sRequestLock) {
+            return setupOrClearBcb(true, command);
+        }
+    }
+
+    @Override // Binder call
+    public void rebootRecoveryWithCommand(String command) {
+        if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+        synchronized (sRequestLock) {
+            if (!setupOrClearBcb(true, command)) {
+                return;
+            }
+
+            // Having set up the BCB, go ahead and reboot.
+            PowerManager pm = mInjector.getPowerManager();
+            pm.reboot(PowerManager.REBOOT_RECOVERY);
+        }
+    }
+
+    /**
+     * Check if any of the init services is still running. If so, we cannot
+     * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+     * it may break the socket communication since init creates / deletes
+     * the socket (/dev/socket/uncrypt) on service start / exit.
+     */
+    private boolean checkAndWaitForUncryptService() {
+        for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+            final String uncryptService = mInjector.systemPropertiesGet(INIT_SERVICE_UNCRYPT);
+            final String setupBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_SETUP_BCB);
+            final String clearBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_CLEAR_BCB);
+            final boolean busy = "running".equals(uncryptService)
+                    || "running".equals(setupBcbService) || "running".equals(clearBcbService);
+            if (DEBUG) {
+                Slog.i(TAG, "retry: " + retry + " busy: " + busy
+                        + " uncrypt: [" + uncryptService + "]"
+                        + " setupBcb: [" + setupBcbService + "]"
+                        + " clearBcb: [" + clearBcbService + "]");
+            }
+
+            if (!busy) {
+                return true;
+            }
+
+            try {
+                mInjector.threadSleep(1000);
+            } catch (InterruptedException e) {
+                Slog.w(TAG, "Interrupted:", e);
+            }
+        }
+
+        return false;
+    }
+
+    private boolean setupOrClearBcb(boolean isSetup, String command) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+
+        final boolean available = checkAndWaitForUncryptService();
+        if (!available) {
+            Slog.e(TAG, "uncrypt service is unavailable.");
+            return false;
+        }
+
+        if (isSetup) {
+            mInjector.systemPropertiesSet("ctl.start", "setup-bcb");
+        } else {
+            mInjector.systemPropertiesSet("ctl.start", "clear-bcb");
+        }
+
+        // Connect to the uncrypt service socket.
+        UncryptSocket socket = mInjector.connectService();
+        if (socket == null) {
+            Slog.e(TAG, "Failed to connect to uncrypt socket");
+            return false;
+        }
+
+        try {
+            // Send the BCB commands if it's to setup BCB.
+            if (isSetup) {
+                socket.sendCommand(command);
+            }
+
+            // Read the status from the socket.
+            int status = socket.getPercentageUncrypted();
+
+            // Ack receipt of the status code. uncrypt waits for the ack so
+            // the socket won't be destroyed before we receive the code.
+            socket.sendAck();
+
+            if (status == 100) {
+                Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear")
+                        + " bcb successfully finished.");
+            } else {
+                // Error in /system/bin/uncrypt.
+                Slog.e(TAG, "uncrypt failed with status: " + status);
+                return false;
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "IOException when communicating with uncrypt:", e);
+            return false;
+        } finally {
+            socket.close();
+        }
+
+        return true;
+    }
+
+    /**
+     * Provides a wrapper for the low-level details of framing packets sent to the uncrypt
+     * socket.
+     */
+    public static class UncryptSocket {
+        private LocalSocket mLocalSocket;
+        private DataInputStream mInputStream;
+        private DataOutputStream mOutputStream;
+
+        /**
+         * Attempt to connect to the uncrypt service. Connection will be retried for up to
+         * {@link #SOCKET_CONNECTION_MAX_RETRY} times. If the connection is unsuccessful, the
+         * socket will be closed. If the connection is successful, the connection must be closed
+         * by the caller.
+         *
+         * @return true if connection was successful, false if unsuccessful
+         */
+        public boolean connectService() {
+            mLocalSocket = new LocalSocket();
+            boolean done = false;
+            // The uncrypt socket will be created by init upon receiving the
+            // service request. It may not be ready by this point. So we will
+            // keep retrying until success or reaching timeout.
+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+                try {
+                    mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+                            LocalSocketAddress.Namespace.RESERVED));
+                    done = true;
+                    break;
+                } catch (IOException ignored) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        Slog.w(TAG, "Interrupted:", e);
+                    }
+                }
+            }
+            if (!done) {
+                Slog.e(TAG, "Timed out connecting to uncrypt socket");
+                close();
+                return false;
+            }
+
+            try {
+                mInputStream = new DataInputStream(mLocalSocket.getInputStream());
+                mOutputStream = new DataOutputStream(mLocalSocket.getOutputStream());
+            } catch (IOException e) {
+                close();
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * Sends a command to the uncrypt service.
+         *
+         * @param command command to send to the uncrypt service
+         * @throws IOException if the socket is closed or there was an error writing to the socket
+         */
+        public void sendCommand(String command) throws IOException {
+            if (mLocalSocket.isClosed()) {
+                throw new IOException("socket is closed");
+            }
+
+            byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8);
+            mOutputStream.writeInt(cmdUtf8.length);
+            mOutputStream.write(cmdUtf8, 0, cmdUtf8.length);
+        }
+
+        /**
+         * Reads the status from the uncrypt service which is usually represented as a percentage.
+         * @return an integer representing the percentage completed
+         * @throws IOException if the socket was closed or there was an error reading the socket
+         */
+        public int getPercentageUncrypted() throws IOException {
+            if (mLocalSocket.isClosed()) {
+                throw new IOException("socket is closed");
+            }
+
+            return mInputStream.readInt();
+        }
+
+        /**
+         * Sends a confirmation to the uncrypt service.
+         * @throws IOException if the socket was closed or there was an error writing to the socket
+         */
+        public void sendAck() throws IOException {
+            if (mLocalSocket.isClosed()) {
+                throw new IOException("socket is closed");
+            }
+
+            mOutputStream.writeInt(0);
+        }
+
+        /**
+         * Closes the socket and all underlying data streams.
+         */
+        public void close() {
+            IoUtils.closeQuietly(mInputStream);
+            IoUtils.closeQuietly(mOutputStream);
+            IoUtils.closeQuietly(mLocalSocket);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 56e1d08..cae09ea3 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -20,7 +20,7 @@
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.os.storage.StorageManager;
 import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
 import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -52,17 +52,18 @@
     }
 
     /**
-     * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code
-     * packageRollbackInfo} with the inodes of the CE user data snapshot folders.
+     * Creates an app data snapshot for a specified {@code packageRollbackInfo} and the specified
+     * {@code userIds}. Updates said {@code packageRollbackInfo} with the inodes of the CE user data
+     * snapshot folders.
      */
-    public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) {
-        final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray();
-        for (int user : installedUsers) {
+    public void snapshotAppData(
+            int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) {
+        for (int user : userIds) {
             final int storageFlags;
             if (isUserCredentialLocked(user)) {
                 // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
                 // across app user data until the user unlocks their device.
-                Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
+                Slog.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
                 storageFlags = Installer.FLAG_STORAGE_DE;
                 packageRollbackInfo.addPendingBackup(user);
             } else {
@@ -76,10 +77,11 @@
                     packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode);
                 }
             } catch (InstallerException ie) {
-                Log.e(TAG, "Unable to create app data snapshot for: "
+                Slog.e(TAG, "Unable to create app data snapshot for: "
                         + packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
             }
         }
+        packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
     }
 
     /**
@@ -96,14 +98,14 @@
 
         final IntArray pendingBackups = packageRollbackInfo.getPendingBackups();
         final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores();
-        boolean changedRollbackData = false;
+        boolean changedRollback = false;
 
         // If we still have a userdata backup pending for this user, it implies that the user
         // hasn't unlocked their device between the point of backup and the point of restore,
         // so the data cannot have changed. We simply skip restoring CE data in this case.
         if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) {
             pendingBackups.remove(pendingBackups.indexOf(userId));
-            changedRollbackData = true;
+            changedRollback = true;
         } else {
             // There's no pending CE backup for this user, which means that we successfully
             // managed to backup data for the user, which means we seek to restore it
@@ -111,7 +113,7 @@
                 // We've encountered a user that hasn't unlocked on a FBE device, so we can't
                 // copy across app user data until the user unlocks their device.
                 pendingRestores.add(new RestoreInfo(userId, appId, seInfo));
-                changedRollbackData = true;
+                changedRollback = true;
             } else {
                 // This user has unlocked, we can proceed to restore both CE and DE data.
                 storageFlags = storageFlags | Installer.FLAG_STORAGE_CE;
@@ -122,11 +124,11 @@
             mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo,
                     userId, rollbackId, storageFlags);
         } catch (InstallerException ie) {
-            Log.e(TAG, "Unable to restore app data snapshot: "
+            Slog.e(TAG, "Unable to restore app data snapshot: "
                         + packageRollbackInfo.getPackageName(), ie);
         }
 
-        return changedRollbackData;
+        return changedRollback;
     }
 
     /**
@@ -148,7 +150,7 @@
                 ceSnapshotInodes.delete(user);
             }
         } catch (InstallerException ie) {
-            Log.e(TAG, "Unable to delete app data snapshot for "
+            Slog.e(TAG, "Unable to delete app data snapshot for "
                         + packageRollbackInfo.getPackageName(), ie);
         }
     }
@@ -158,29 +160,29 @@
      * Packages pending backup for the given user are added to {@code pendingBackupPackages} along
      * with their corresponding {@code PackageRollbackInfo}.
      *
-     * @return the list of {@code RollbackData} that has pending backups. Note that some of the
+     * @return the list of rollbacks that have pending backups. Note that some of the
      *         backups won't be performed, because they might be counteracted by pending restores.
      */
-    private static List<RollbackData> computePendingBackups(int userId,
+    private static List<Rollback> computePendingBackups(int userId,
             Map<String, PackageRollbackInfo> pendingBackupPackages,
-            List<RollbackData> rollbacks) {
-        List<RollbackData> rd = new ArrayList<>();
+            List<Rollback> rollbacks) {
+        List<Rollback> rollbacksWithPendingBackups = new ArrayList<>();
 
-        for (RollbackData data : rollbacks) {
-            for (PackageRollbackInfo info : data.info.getPackages()) {
+        for (Rollback rollback : rollbacks) {
+            for (PackageRollbackInfo info : rollback.info.getPackages()) {
                 final IntArray pendingBackupUsers = info.getPendingBackups();
                 if (pendingBackupUsers != null) {
                     final int idx = pendingBackupUsers.indexOf(userId);
                     if (idx != -1) {
                         pendingBackupPackages.put(info.getPackageName(), info);
-                        if (rd.indexOf(data) == -1) {
-                            rd.add(data);
+                        if (rollbacksWithPendingBackups.indexOf(rollback) == -1) {
+                            rollbacksWithPendingBackups.add(rollback);
                         }
                     }
                 }
             }
         }
-        return rd;
+        return rollbacksWithPendingBackups;
     }
 
     /**
@@ -188,45 +190,45 @@
      * Packages pending restore are added to {@code pendingRestores} along with their corresponding
      * {@code PackageRollbackInfo}.
      *
-     * @return the list of {@code RollbackData} that has pending restores. Note that some of the
+     * @return the list of rollbacks that have pending restores. Note that some of the
      *         restores won't be performed, because they might be counteracted by pending backups.
      */
-    private static List<RollbackData> computePendingRestores(int userId,
+    private static List<Rollback> computePendingRestores(int userId,
             Map<String, PackageRollbackInfo> pendingRestorePackages,
-            List<RollbackData> rollbacks) {
-        List<RollbackData> rd = new ArrayList<>();
+            List<Rollback> rollbacks) {
+        List<Rollback> rollbacksWithPendingRestores = new ArrayList<>();
 
-        for (RollbackData data : rollbacks) {
-            for (PackageRollbackInfo info : data.info.getPackages()) {
+        for (Rollback rollback : rollbacks) {
+            for (PackageRollbackInfo info : rollback.info.getPackages()) {
                 final RestoreInfo ri = info.getRestoreInfo(userId);
                 if (ri != null) {
                     pendingRestorePackages.put(info.getPackageName(), info);
-                    if (rd.indexOf(data) == -1) {
-                        rd.add(data);
+                    if (rollbacksWithPendingRestores.indexOf(rollback) == -1) {
+                        rollbacksWithPendingRestores.add(rollback);
                     }
                 }
             }
         }
 
-        return rd;
+        return rollbacksWithPendingRestores;
     }
 
     /**
-     * Commits the list of pending backups and restores for a given {@code userId}. For the pending
-     * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
-     * to a inode of theirs CE user data snapshot.
+     * Commits the list of pending backups and restores for a given {@code userId}. For rollbacks
+     * with pending backups, updates the {@code Rollback} instance with a mapping from
+     * {@code userId} to inode of the CE user data snapshot.
      *
-     * @return the set of {@code RollbackData} that have been changed and should be stored on disk.
+     * @return the set of rollbacks with changes that should be stored on disk.
      */
-    public Set<RollbackData> commitPendingBackupAndRestoreForUser(int userId,
-            List<RollbackData> rollbacks) {
+    public Set<Rollback> commitPendingBackupAndRestoreForUser(int userId,
+            List<Rollback> rollbacks) {
 
         final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>();
-        final List<RollbackData> pendingBackups = computePendingBackups(userId,
+        final List<Rollback> pendingBackups = computePendingBackups(userId,
                 pendingBackupPackages, rollbacks);
 
         final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>();
-        final List<RollbackData> pendingRestores = computePendingRestores(userId,
+        final List<Rollback> pendingRestores = computePendingRestores(userId,
                 pendingRestorePackages, rollbacks);
 
         // First remove unnecessary backups, i.e. when user did not unlock their phone between the
@@ -246,18 +248,19 @@
         }
 
         if (!pendingBackupPackages.isEmpty()) {
-            for (RollbackData data : pendingBackups) {
-                for (PackageRollbackInfo info : data.info.getPackages()) {
+            for (Rollback rollback : pendingBackups) {
+                for (PackageRollbackInfo info : rollback.info.getPackages()) {
                     final IntArray pendingBackupUsers = info.getPendingBackups();
                     final int idx = pendingBackupUsers.indexOf(userId);
                     if (idx != -1) {
                         try {
                             long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(),
-                                    userId, data.info.getRollbackId(), Installer.FLAG_STORAGE_CE);
+                                    userId, rollback.info.getRollbackId(),
+                                    Installer.FLAG_STORAGE_CE);
                             info.putCeSnapshotInode(userId, ceSnapshotInode);
                             pendingBackupUsers.remove(idx);
                         } catch (InstallerException ie) {
-                            Log.e(TAG,
+                            Slog.e(TAG,
                                     "Unable to create app data snapshot for: "
                                     + info.getPackageName() + ", userId: " + userId, ie);
                         }
@@ -267,17 +270,17 @@
         }
 
         if (!pendingRestorePackages.isEmpty()) {
-            for (RollbackData data : pendingRestores) {
-                for (PackageRollbackInfo info : data.info.getPackages()) {
+            for (Rollback rollback : pendingRestores) {
+                for (PackageRollbackInfo info : rollback.info.getPackages()) {
                     final RestoreInfo ri = info.getRestoreInfo(userId);
                     if (ri != null) {
                         try {
                             mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
-                                    ri.seInfo, userId, data.info.getRollbackId(),
+                                    ri.seInfo, userId, rollback.info.getRollbackId(),
                                     Installer.FLAG_STORAGE_CE);
                             info.removeRestoreInfo(ri);
                         } catch (InstallerException ie) {
-                            Log.e(TAG, "Unable to restore app data snapshot for: "
+                            Slog.e(TAG, "Unable to restore app data snapshot for: "
                                     + info.getPackageName(), ie);
                         }
                     }
@@ -285,7 +288,7 @@
             }
         }
 
-        final Set<RollbackData> changed = new HashSet<>(pendingBackups);
+        final Set<Rollback> changed = new HashSet<>(pendingBackups);
         changed.addAll(pendingRestores);
         return changed;
     }
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/Rollback.java
similarity index 85%
rename from services/core/java/com/android/server/rollback/RollbackData.java
rename to services/core/java/com/android/server/rollback/Rollback.java
index b37e268..0d5746b 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -32,7 +32,7 @@
  * Information about a rollback available for a set of atomically installed
  * packages.
  */
-class RollbackData {
+class Rollback {
     @IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
             ROLLBACK_STATE_ENABLING,
             ROLLBACK_STATE_AVAILABLE,
@@ -102,13 +102,13 @@
     public boolean restoreUserDataInProgress = false;
 
     /**
-     * Constructs a new, empty RollbackData instance.
+     * Constructs a new, empty Rollback instance.
      *
      * @param rollbackId the id of the rollback.
      * @param backupDir the directory where the rollback data is stored.
      * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
      */
-    RollbackData(int rollbackId, File backupDir, int stagedSessionId) {
+    Rollback(int rollbackId, File backupDir, int stagedSessionId) {
         this.info = new RollbackInfo(rollbackId,
                 /* packages */ new ArrayList<>(),
                 /* isStaged */ stagedSessionId != -1,
@@ -121,9 +121,9 @@
     }
 
     /**
-     * Constructs a RollbackData instance with full rollback data information.
+     * Constructs a pre-populated Rollback instance.
      */
-    RollbackData(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
+    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
             @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) {
         this.info = info;
         this.backupDir = backupDir;
@@ -143,9 +143,9 @@
 
     static String rollbackStateToString(@RollbackState int state) {
         switch (state) {
-            case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
-            case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
-            case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
+            case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
+            case Rollback.ROLLBACK_STATE_AVAILABLE: return "available";
+            case Rollback.ROLLBACK_STATE_COMMITTED: return "committed";
         }
         throw new AssertionError("Invalid rollback state: " + state);
     }
@@ -153,9 +153,9 @@
     static @RollbackState int rollbackStateFromString(String state)
             throws ParseException {
         switch (state) {
-            case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
-            case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
-            case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
+            case "enabling": return Rollback.ROLLBACK_STATE_ENABLING;
+            case "available": return Rollback.ROLLBACK_STATE_AVAILABLE;
+            case "committed": return Rollback.ROLLBACK_STATE_COMMITTED;
         }
         throw new ParseException("Invalid rollback state: " + state, 0);
     }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e107c9a..42f3e2fd 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -45,14 +45,13 @@
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.UserHandle;   // duped to avoid merge conflict
-import android.os.UserManager;  // out of order to avoid merge conflict
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.SparseLongArray;
 
@@ -76,6 +75,7 @@
 import java.util.List;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -110,14 +110,13 @@
     @GuardedBy("mLock")
     private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
 
-    // Package rollback data for rollbacks we are in the process of enabling.
+    // Rollbacks we are in the process of enabling.
     @GuardedBy("mLock")
     private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
 
     // The list of all rollbacks, including available and committed rollbacks.
-    // This list is null until the rollback data has been loaded.
     @GuardedBy("mLock")
-    private List<RollbackData> mRollbacks;
+    private final List<Rollback> mRollbacks;
 
     private final RollbackStore mRollbackStore;
 
@@ -128,7 +127,7 @@
     private final AppDataRollbackHelper mAppDataRollbackHelper;
 
     // This field stores the difference in Millis between the uptime (millis since device
-    // has booted) and current time (device wall clock) - it's used to update rollback data
+    // has booted) and current time (device wall clock) - it's used to update rollback
     // timestamps when the time is changed, by the user or by change of timezone.
     // No need for guarding with lock because value is only accessed in handler thread.
     private long  mRelativeBootTime = calculateRelativeBootTime();
@@ -139,29 +138,25 @@
         // SystemService#onStart.
         mInstaller = new Installer(mContext);
         mInstaller.onStart();
-        mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
-        mHandlerThread.start();
-
-        // Monitor the handler thread
-        Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
 
         mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
 
         mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
         mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
 
-        // Kick off loading of the rollback data from strorage in a background
-        // thread.
-        // TODO: Consider loading the rollback data directly here instead, to
-        // avoid the need to call ensureRollbackDataLoaded every time before
-        // accessing the rollback data?
-        // TODO: Test that this kicks off initial scheduling of rollback
-        // expiration.
-        getHandler().post(() -> ensureRollbackDataLoaded());
+        // Load rollback data from device storage.
+        synchronized (mLock) {
+            mRollbacks = mRollbackStore.loadRollbacks();
+            for (Rollback rollback : mRollbacks) {
+                mAllocatedRollbackIds.put(rollback.info.getRollbackId(), true);
+            }
+        }
 
-        // TODO: Make sure to register these call backs when a new user is
-        // added too.
-        SessionCallback sessionCallback = new SessionCallback();
+        // Kick off and start monitoring the handler thread.
+        mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+        mHandlerThread.start();
+        Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
+
         for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
             registerUserCallbacks(userInfo.getUserHandle());
         }
@@ -171,7 +166,7 @@
         try {
             enableRollbackFilter.addDataType("application/vnd.android.package-archive");
         } catch (IntentFilter.MalformedMimeTypeException e) {
-            Log.e(TAG, "addDataType", e);
+            Slog.e(TAG, "addDataType", e);
         }
 
         mContext.registerReceiver(new BroadcastReceiver() {
@@ -182,16 +177,14 @@
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
                     int installFlags = intent.getIntExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
-                    int[] installedUsers = intent.getIntArrayExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
                     int user = intent.getIntExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0);
 
                     File newPackageCodePath = new File(intent.getData().getPath());
 
                     getHandler().post(() -> {
-                        boolean success = enableRollback(installFlags, newPackageCodePath,
-                                installedUsers, user, token);
+                        boolean success =
+                                enableRollback(installFlags, newPackageCodePath, user, token);
                         int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
                         if (!success) {
                             ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
@@ -251,13 +244,10 @@
     private void registerUserCallbacks(UserHandle user) {
         Context context = getContextAsUser(user);
         if (context == null) {
-            Log.e(TAG, "Unable to register user callbacks for user " + user);
+            Slog.e(TAG, "Unable to register user callbacks for user " + user);
             return;
         }
 
-        // TODO: Reuse the same SessionCallback and broadcast receiver
-        // instances, rather than creating new instances for each user.
-
         context.getPackageManager().getPackageInstaller()
                 .registerSessionCallback(new SessionCallback(), getHandler());
 
@@ -281,44 +271,15 @@
         }, filter, null, getHandler());
     }
 
-    /**
-     * This method posts a blocking call to the handler thread, so it should not be called from
-     * that same thread.
-     * @throws {@link IllegalStateException} if called from {@link #mHandlerThread}
-     */
     @Override
     public ParceledListSlice getAvailableRollbacks() {
         enforceManageRollbacks("getAvailableRollbacks");
-        if (Thread.currentThread().equals(mHandlerThread)) {
-            Log.wtf(TAG, "Calling getAvailableRollbacks from mHandlerThread "
-                    + "causes a deadlock");
-            throw new IllegalStateException("Cannot call RollbackManager#getAvailableRollbacks "
-                    + "from the handler thread!");
-        }
-
-        // Wait for the handler thread to get the list of available rollbacks
-        // to get the most up-to-date results. This is intended to reduce test
-        // flakiness when checking available rollbacks immediately after
-        // installing a package with rollback enabled.
-        final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
-        getHandler().post(() -> result.offer(true));
-
-        try {
-            result.take();
-        } catch (InterruptedException ie) {
-            // We may not get the most up-to-date information, but whatever we
-            // can get now is better than nothing, so log but otherwise ignore
-            // the exception.
-            Log.w(TAG, "Interrupted while waiting for handler thread in getAvailableRollbacks");
-        }
-
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
             List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE) {
-                    rollbacks.add(data.info);
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) {
+                    rollbacks.add(rollback.info);
                 }
             }
             return new ParceledListSlice<>(rollbacks);
@@ -326,16 +287,15 @@
     }
 
     @Override
-    public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
+    public ParceledListSlice<RollbackInfo> getRecentlyCommittedRollbacks() {
         enforceManageRollbacks("getRecentlyCommittedRollbacks");
 
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
             List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
-                    rollbacks.add(data.info);
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
+                    rollbacks.add(rollback.info);
                 }
             }
             return new ParceledListSlice<>(rollbacks);
@@ -345,7 +305,7 @@
     @Override
     public void commitRollback(int rollbackId, ParceledListSlice causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        enforceManageRollbacks("executeRollback");
+        enforceManageRollbacks("commitRollback");
 
         final int callingUid = Binder.getCallingUid();
         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -365,13 +325,11 @@
                 final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
 
                 synchronized (mLock) {
-                    ensureRollbackDataLoadedLocked();
-
-                    Iterator<RollbackData> iter = mRollbacks.iterator();
+                    Iterator<Rollback> iter = mRollbacks.iterator();
                     while (iter.hasNext()) {
-                        RollbackData data = iter.next();
-                        data.timestamp = data.timestamp.plusMillis(timeDifference);
-                        saveRollbackData(data);
+                        Rollback rollback = iter.next();
+                        rollback.timestamp = rollback.timestamp.plusMillis(timeDifference);
+                        saveRollback(rollback);
                     }
                 }
             }
@@ -393,10 +351,10 @@
      */
     private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        Log.i(TAG, "Initiating rollback");
+        Slog.i(TAG, "Initiating rollback");
 
-        RollbackData data = getRollbackForId(rollbackId);
-        if (data == null || data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+        Rollback rollback = getRollbackForId(rollbackId);
+        if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
             sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
                     "Rollback unavailable");
             return;
@@ -404,7 +362,7 @@
 
         // Get a context for the caller to use to install the downgraded
         // version of the package.
-        Context context = null;
+        final Context context;
         try {
             context = mContext.createPackageContext(callerPackageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
@@ -420,14 +378,14 @@
                     PackageInstaller.SessionParams.MODE_FULL_INSTALL);
             parentParams.setRequestDowngrade(true);
             parentParams.setMultiPackage();
-            if (data.isStaged()) {
+            if (rollback.isStaged()) {
                 parentParams.setStaged();
             }
 
             int parentSessionId = packageInstaller.createSession(parentParams);
             PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId);
 
-            for (PackageRollbackInfo info : data.info.getPackages()) {
+            for (PackageRollbackInfo info : rollback.info.getPackages()) {
                 PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                         PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                 // TODO: We can't get the installerPackageName for apex
@@ -442,7 +400,7 @@
                 params.setRequestDowngrade(true);
                 params.setRequiredInstalledVersionCode(
                         info.getVersionRolledBackFrom().getLongVersionCode());
-                if (data.isStaged()) {
+                if (rollback.isStaged()) {
                     params.setStaged();
                 }
                 if (info.isApex()) {
@@ -450,9 +408,8 @@
                 }
                 int sessionId = packageInstaller.createSession(params);
                 PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
                 File[] packageCodePaths = RollbackStore.getPackageCodePaths(
-                        data, info.getPackageName());
+                        rollback, info.getPackageName());
                 if (packageCodePaths == null) {
                     sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
                             "Backup copy of package inaccessible");
@@ -493,8 +450,8 @@
                                     // TODO: Could this cause a rollback to be
                                     // resurrected if it should otherwise have
                                     // expired by now?
-                                    data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
-                                    data.restoreUserDataInProgress = false;
+                                    rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+                                    rollback.restoreUserDataInProgress = false;
                                 }
                                 sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL,
                                         "Rollback downgrade install failed: "
@@ -504,35 +461,37 @@
                             }
 
                             synchronized (mLock) {
-                                if (!data.isStaged()) {
+                                if (!rollback.isStaged()) {
                                     // All calls to restoreUserData should have
                                     // completed by now for a non-staged install.
-                                    data.restoreUserDataInProgress = false;
+                                    rollback.restoreUserDataInProgress = false;
                                 }
 
-                                data.info.setCommittedSessionId(parentSessionId);
-                                data.info.getCausePackages().addAll(causePackages);
+                                rollback.info.setCommittedSessionId(parentSessionId);
+                                rollback.info.getCausePackages().addAll(causePackages);
                             }
-                            mRollbackStore.deletePackageCodePaths(data);
-                            saveRollbackData(data);
+                            mRollbackStore.deletePackageCodePaths(rollback);
+                            saveRollback(rollback);
 
                             sendSuccess(statusReceiver);
 
                             Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
 
-                            mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
-                                    Manifest.permission.MANAGE_ROLLBACKS);
+                            for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
+                                mContext.sendBroadcastAsUser(broadcast, userInfo.getUserHandle(),
+                                        Manifest.permission.MANAGE_ROLLBACKS);
+                            }
                         });
                     }
             );
 
             synchronized (mLock) {
-                data.state = RollbackData.ROLLBACK_STATE_COMMITTED;
-                data.restoreUserDataInProgress = true;
+                rollback.state = Rollback.ROLLBACK_STATE_COMMITTED;
+                rollback.restoreUserDataInProgress = true;
             }
             parentSession.commit(receiver.getIntentSender());
         } catch (IOException e) {
-            Log.e(TAG, "Rollback failed", e);
+            Slog.e(TAG, "Rollback failed", e);
             sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
                     "IOException: " + e.toString());
             return;
@@ -545,13 +504,21 @@
                 Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "reloadPersistedData");
 
-        synchronized (mLock) {
-            mRollbacks = null;
-        }
+        CountDownLatch latch = new CountDownLatch(1);
         getHandler().post(() -> {
             updateRollbackLifetimeDurationInMillis();
-            ensureRollbackDataLoaded();
+            synchronized (mLock) {
+                mRollbacks.clear();
+                mRollbacks.addAll(mRollbackStore.loadRollbacks());
+            }
+            latch.countDown();
         });
+
+        try {
+            latch.await();
+        } catch (InterruptedException ie) {
+            throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+        }
     }
 
     @Override
@@ -560,14 +527,21 @@
                 Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "expireRollbackForPackage");
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            Iterator<RollbackData> iter = mRollbacks.iterator();
+            Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
-                RollbackData data = iter.next();
-                for (PackageRollbackInfo info : data.info.getPackages()) {
+                Rollback rollback = iter.next();
+                for (PackageRollbackInfo info : rollback.info.getPackages()) {
                     if (info.getPackageName().equals(packageName)) {
                         iter.remove();
-                        deleteRollback(data);
+                        deleteRollback(rollback);
+                        break;
+                    }
+                }
+            }
+            for (NewRollback newRollback : mNewRollbacks) {
+                for (PackageRollbackInfo info : newRollback.rollback.info.getPackages()) {
+                    if (info.getPackageName().equals(packageName)) {
+                        newRollback.isCancelled = true;
                         break;
                     }
                 }
@@ -575,18 +549,32 @@
         }
     }
 
+    @Override
+    public void blockRollbackManager(long millis) {
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
+                "blockRollbackManager");
+        getHandler().post(() -> {
+            try {
+                Thread.sleep(millis);
+            } catch (InterruptedException e) {
+                throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+            }
+        });
+    }
+
     void onUnlockUser(int userId) {
         getHandler().post(() -> {
-            final List<RollbackData> rollbacks;
+            final List<Rollback> rollbacks;
             synchronized (mLock) {
                 rollbacks = new ArrayList<>(mRollbacks);
             }
 
-            final Set<RollbackData> changed =
+            final Set<Rollback> changed =
                     mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId, rollbacks);
 
-            for (RollbackData rd : changed) {
-                saveRollbackData(rd);
+            for (Rollback rollback : changed) {
+                saveRollback(rollback);
             }
         });
     }
@@ -609,20 +597,19 @@
         getHandler().post(() -> {
             // Check to see if any rollback-enabled staged sessions or staged
             // rollback sessions been applied.
-            List<RollbackData> enabling = new ArrayList<>();
-            List<RollbackData> restoreInProgress = new ArrayList<>();
+            List<Rollback> enabling = new ArrayList<>();
+            List<Rollback> restoreInProgress = new ArrayList<>();
             Set<String> apexPackageNames = new HashSet<>();
             synchronized (mLock) {
-                ensureRollbackDataLoadedLocked();
-                for (RollbackData data : mRollbacks) {
-                    if (data.isStaged()) {
-                        if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
-                            enabling.add(data);
-                        } else if (data.restoreUserDataInProgress) {
-                            restoreInProgress.add(data);
+                for (Rollback rollback : mRollbacks) {
+                    if (rollback.isStaged()) {
+                        if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+                            enabling.add(rollback);
+                        } else if (rollback.restoreUserDataInProgress) {
+                            restoreInProgress.add(rollback);
                         }
 
-                        for (PackageRollbackInfo info : data.info.getPackages()) {
+                        for (PackageRollbackInfo info : rollback.info.getPackages()) {
                             if (info.isApex()) {
                                 apexPackageNames.add(info.getPackageName());
                             }
@@ -631,35 +618,32 @@
                 }
             }
 
-            for (RollbackData data : enabling) {
+            for (Rollback rollback : enabling) {
                 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
                 PackageInstaller.SessionInfo session = installer.getSessionInfo(
-                        data.stagedSessionId);
-                // TODO: What if session is null?
-                if (session != null) {
-                    if (session.isStagedSessionApplied()) {
-                        makeRollbackAvailable(data);
-                    } else if (session.isStagedSessionFailed()) {
-                        // TODO: Do we need to remove this from
-                        // mRollbacks, or is it okay to leave as
-                        // unavailable until the next reboot when it will go
-                        // away on its own?
-                        deleteRollback(data);
-                    }
+                        rollback.stagedSessionId);
+                if (session == null || session.isStagedSessionFailed()) {
+                    // TODO: Do we need to remove this from
+                    // mRollbacks, or is it okay to leave as
+                    // unavailable until the next reboot when it will go
+                    // away on its own?
+                    deleteRollback(rollback);
+                } else if (session.isStagedSessionApplied()) {
+                    makeRollbackAvailable(rollback);
                 }
             }
 
-            for (RollbackData data : restoreInProgress) {
+            for (Rollback rollback : restoreInProgress) {
                 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
                 PackageInstaller.SessionInfo session = installer.getSessionInfo(
-                        data.stagedSessionId);
+                        rollback.stagedSessionId);
                 // TODO: What if session is null?
                 if (session != null) {
                     if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
                         synchronized (mLock) {
-                            data.restoreUserDataInProgress = false;
+                            rollback.restoreUserDataInProgress = false;
                         }
-                        saveRollbackData(data);
+                        saveRollback(rollback);
                     }
                 }
             }
@@ -676,42 +660,6 @@
     }
 
     /**
-     * Load rollback data from storage if it has not already been loaded.
-     * After calling this funciton, mAvailableRollbacks and
-     * mRecentlyExecutedRollbacks will be non-null.
-     */
-    private void ensureRollbackDataLoaded() {
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-        }
-    }
-
-    /**
-     * Load rollback data from storage if it has not already been loaded.
-     * After calling this function, mRollbacks will be non-null.
-     */
-    @GuardedBy("mLock")
-    private void ensureRollbackDataLoadedLocked() {
-        if (mRollbacks == null) {
-            loadAllRollbackDataLocked();
-        }
-    }
-
-    /**
-     * Load all rollback data from storage.
-     * Note: We do potentially heavy IO here while holding mLock, because we
-     * have to have the rollback data loaded before we can do anything else
-     * meaningful.
-     */
-    @GuardedBy("mLock")
-    private void loadAllRollbackDataLocked() {
-        mRollbacks = mRollbackStore.loadAllRollbackData();
-        for (RollbackData data : mRollbacks) {
-            mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
-        }
-    }
-
-    /**
      * Called when a package has been replaced with a different version.
      * Removes all backups for the package not matching the currently
      * installed package version.
@@ -722,20 +670,19 @@
         VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
 
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            Iterator<RollbackData> iter = mRollbacks.iterator();
+            Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
-                RollbackData data = iter.next();
+                Rollback rollback = iter.next();
                 // TODO: Should we remove rollbacks in the ENABLING state here?
-                if (data.state == RollbackData.ROLLBACK_STATE_AVAILABLE
-                        || data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
-                    for (PackageRollbackInfo info : data.info.getPackages()) {
+                if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE
+                        || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) {
+                    for (PackageRollbackInfo info : rollback.info.getPackages()) {
                         if (info.getPackageName().equals(packageName)
                                 && !packageVersionsEqual(
                                     info.getVersionRolledBackFrom(),
                                     installedVersion)) {
                             iter.remove();
-                            deleteRollback(data);
+                            deleteRollback(rollback);
                             break;
                         }
                     }
@@ -761,7 +708,7 @@
      */
     private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status,
             String message) {
-        Log.e(TAG, message);
+        Slog.e(TAG, message);
         try {
             final Intent fillIn = new Intent();
             fillIn.putExtra(RollbackManager.EXTRA_STATUS, status);
@@ -791,19 +738,18 @@
         Instant now = Instant.now();
         Instant oldest = null;
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-
-            Iterator<RollbackData> iter = mRollbacks.iterator();
+            Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
-                RollbackData data = iter.next();
-                if (data.state != RollbackData.ROLLBACK_STATE_AVAILABLE) {
+                Rollback rollback = iter.next();
+                if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) {
                     continue;
                 }
-                if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
+                if (!now.isBefore(
+                            rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
                     iter.remove();
-                    deleteRollback(data);
-                } else if (oldest == null || oldest.isAfter(data.timestamp)) {
-                    oldest = data.timestamp;
+                    deleteRollback(rollback);
+                } else if (oldest == null || oldest.isAfter(rollback.timestamp)) {
+                    oldest = rollback.timestamp;
                 }
             }
         }
@@ -858,13 +804,12 @@
      *
      * @param installFlags information about what is being installed.
      * @param newPackageCodePath path to the package about to be installed.
-     * @param installedUsers the set of users for which a given package is installed.
      * @param user the user that owns the install session to enable rollback on.
      * @param token the distinct rollback token sent by package manager.
      * @return true if enabling the rollback succeeds, false otherwise.
      */
-    private boolean enableRollback(int installFlags, File newPackageCodePath,
-            int[] installedUsers, @UserIdInt int user, int token) {
+    private boolean enableRollback(
+            int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
 
         // Find the session id associated with this install.
         // TODO: It would be nice if package manager or package installer told
@@ -876,7 +821,7 @@
         // session.
         final Context context = getContextAsUser(UserHandle.of(user));
         if (context == null) {
-            Log.e(TAG, "Unable to create context for install session user.");
+            Slog.e(TAG, "Unable to create context for install session user.");
             return false;
         }
 
@@ -903,45 +848,21 @@
         }
 
         if (parentSession == null || packageSession == null) {
-            Log.e(TAG, "Unable to find session for enabled rollback.");
+            Slog.e(TAG, "Unable to find session for enabled rollback.");
             return false;
         }
 
         // Check to see if this is the apk session for a staged session with
         // rollback enabled.
-        // TODO: This check could be made more efficient.
-        RollbackData rd = null;
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.apkSessionId == parentSession.getSessionId()) {
-                    rd = data;
-                    break;
-                }
-            }
-        }
-
-        if (rd != null) {
-            // This is the apk session for a staged session. We do not need to create a new rollback
-            // for this session.
-            PackageParser.PackageLite newPackage = null;
-            try {
-                newPackage = PackageParser.parsePackageLite(
-                        new File(packageSession.resolvedBaseCodePath), 0);
-            } catch (PackageParser.PackageParserException e) {
-                Log.e(TAG, "Unable to parse new package", e);
-                return false;
-            }
-            String packageName = newPackage.packageName;
-            for (PackageRollbackInfo info : rd.info.getPackages()) {
-                if (info.getPackageName().equals(packageName)) {
-                    info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.apkSessionId == parentSession.getSessionId()) {
+                    // This is the apk session for a staged session with rollback enabled. We do not
+                    // need to create a new rollback for this session.
                     return true;
                 }
             }
-            Log.e(TAG, "Unable to find package in apk session");
-            return false;
         }
 
         NewRollback newRollback;
@@ -957,7 +878,7 @@
         }
         newRollback.addToken(token);
 
-        return enableRollbackForPackageSession(newRollback.data, packageSession, installedUsers);
+        return enableRollbackForPackageSession(newRollback.rollback, packageSession);
     }
 
     /**
@@ -967,21 +888,21 @@
      *
      * @return true on success, false on failure.
      */
-    private boolean enableRollbackForPackageSession(RollbackData data,
-            PackageInstaller.SessionInfo session, @NonNull int[] installedUsers) {
+    private boolean enableRollbackForPackageSession(Rollback rollback,
+            PackageInstaller.SessionInfo session) {
         // TODO: Don't attempt to enable rollback for split installs.
         final int installFlags = session.installFlags;
         if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
-            Log.e(TAG, "Rollback is not enabled.");
+            Slog.e(TAG, "Rollback is not enabled.");
             return false;
         }
         if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-            Log.e(TAG, "Rollbacks not supported for instant app install");
+            Slog.e(TAG, "Rollbacks not supported for instant app install");
             return false;
         }
 
         if (session.resolvedBaseCodePath == null) {
-            Log.e(TAG, "Session code path has not been resolved.");
+            Slog.e(TAG, "Session code path has not been resolved.");
             return false;
         }
 
@@ -990,17 +911,17 @@
         try {
             newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
         } catch (PackageParser.PackageParserException e) {
-            Log.e(TAG, "Unable to parse new package", e);
+            Slog.e(TAG, "Unable to parse new package", e);
             return false;
         }
 
         String packageName = newPackage.packageName;
-        Log.i(TAG, "Enabling rollback for install of " + packageName
+        Slog.i(TAG, "Enabling rollback for install of " + packageName
                 + ", session:" + session.sessionId);
 
         String installerPackageName = session.getInstallerPackageName();
         if (!enableRollbackAllowed(installerPackageName, packageName)) {
-            Log.e(TAG, "Installer " + installerPackageName
+            Slog.e(TAG, "Installer " + installerPackageName
                     + " is not allowed to enable rollback on " + packageName);
             return false;
         }
@@ -1016,7 +937,7 @@
         } catch (PackageManager.NameNotFoundException e) {
             // TODO: Support rolling back fresh package installs rather than
             // fail here. Test this case.
-            Log.e(TAG, packageName + " is not installed");
+            Slog.e(TAG, packageName + " is not installed");
             return false;
         }
 
@@ -1026,24 +947,23 @@
         PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
                 newVersion, installedVersion,
                 new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
-                isApex, IntArray.wrap(installedUsers),
-                new SparseLongArray() /* ceSnapshotInodes */);
+                isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
 
         try {
             ApplicationInfo appInfo = pkgInfo.applicationInfo;
-            RollbackStore.backupPackageCodePath(data, packageName, appInfo.sourceDir);
+            RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir);
             if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) {
                 for (String sourceDir : appInfo.splitSourceDirs) {
-                    RollbackStore.backupPackageCodePath(data, packageName, sourceDir);
+                    RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir);
                 }
             }
         } catch (IOException e) {
-            Log.e(TAG, "Unable to copy package for rollback for " + packageName, e);
+            Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e);
             return false;
         }
 
         synchronized (mLock) {
-            data.info.getPackages().add(packageRollbackInfo);
+            rollback.info.getPackages().add(packageRollbackInfo);
         }
         return true;
     }
@@ -1057,7 +977,7 @@
         }
 
         getHandler().post(() -> {
-            snapshotUserDataInternal(packageName);
+            snapshotUserDataInternal(packageName, userIds);
             restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
             final PackageManagerInternal pmi = LocalServices.getService(
                     PackageManagerInternal.class);
@@ -1065,20 +985,20 @@
         });
     }
 
-    private void snapshotUserDataInternal(String packageName) {
+    private void snapshotUserDataInternal(String packageName, int[] userIds) {
         synchronized (mLock) {
             // staged installs
-            ensureRollbackDataLoadedLocked();
             for (int i = 0; i < mRollbacks.size(); i++) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) {
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) {
                     continue;
                 }
 
-                for (PackageRollbackInfo info : data.info.getPackages()) {
+                for (PackageRollbackInfo info : rollback.info.getPackages()) {
                     if (info.getPackageName().equals(packageName)) {
-                        mAppDataRollbackHelper.snapshotAppData(data.info.getRollbackId(), info);
-                        saveRollbackData(data);
+                        mAppDataRollbackHelper.snapshotAppData(
+                                rollback.info.getRollbackId(), info, userIds);
+                        saveRollback(rollback);
                         break;
                     }
                 }
@@ -1086,11 +1006,11 @@
             // non-staged installs
             PackageRollbackInfo info;
             for (NewRollback rollback : mNewRollbacks) {
-                info = getPackageRollbackInfo(rollback.data, packageName);
+                info = getPackageRollbackInfo(rollback.rollback, packageName);
                 if (info != null) {
-                    mAppDataRollbackHelper.snapshotAppData(rollback.data.info.getRollbackId(),
-                            info);
-                    saveRollbackData(rollback.data);
+                    mAppDataRollbackHelper.snapshotAppData(
+                            rollback.rollback.info.getRollbackId(), info, userIds);
+                    saveRollback(rollback.rollback);
                 }
             }
         }
@@ -1099,32 +1019,31 @@
     private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
             long ceDataInode, String seInfo, int token) {
         PackageRollbackInfo info = null;
-        RollbackData rollbackData = null;
+        Rollback rollback = null;
         synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.restoreUserDataInProgress) {
-                    info = getPackageRollbackInfo(data, packageName);
+                Rollback candidate = mRollbacks.get(i);
+                if (candidate.restoreUserDataInProgress) {
+                    info = getPackageRollbackInfo(candidate, packageName);
                     if (info != null) {
-                        rollbackData = data;
+                        rollback = candidate;
                         break;
                     }
                 }
             }
         }
 
-        if (rollbackData == null) {
+        if (rollback == null) {
             return;
         }
 
         for (int userId : userIds) {
-            final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
-                    rollbackData.info.getRollbackId(), info, userId, appId, seInfo);
+            final boolean changedRollback = mAppDataRollbackHelper.restoreAppData(
+                    rollback.info.getRollbackId(), info, userId, appId, seInfo);
 
             // We've updated metadata about this rollback, so save it to flash.
-            if (changedRollbackData) {
-                saveRollbackData(rollbackData);
+            if (changedRollback) {
+                saveRollback(rollback);
             }
         }
     }
@@ -1143,7 +1062,7 @@
 
             final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
             if (session == null) {
-                Log.e(TAG, "No matching install session for: " + sessionId);
+                Slog.e(TAG, "No matching install session for: " + sessionId);
                 result.offer(false);
                 return;
             }
@@ -1154,9 +1073,8 @@
             }
 
             if (!session.isMultiPackage()) {
-                if (!enableRollbackForPackageSession(newRollback.data, session,
-                            new int[0])) {
-                    Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+                if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
+                    Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
                     result.offer(false);
                     return;
                 }
@@ -1165,13 +1083,12 @@
                     final PackageInstaller.SessionInfo childSession =
                             installer.getSessionInfo(childSessionId);
                     if (childSession == null) {
-                        Log.e(TAG, "No matching child install session for: " + childSessionId);
+                        Slog.e(TAG, "No matching child install session for: " + childSessionId);
                         result.offer(false);
                         return;
                     }
-                    if (!enableRollbackForPackageSession(newRollback.data, childSession,
-                                new int[0])) {
-                        Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
+                    if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
+                        Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
                         result.offer(false);
                         return;
                     }
@@ -1184,7 +1101,7 @@
         try {
             return result.take();
         } catch (InterruptedException ie) {
-            Log.e(TAG, "Interrupted while waiting for notifyStagedSession response");
+            Slog.e(TAG, "Interrupted while waiting for notifyStagedSession response");
             return false;
         }
     }
@@ -1195,21 +1112,20 @@
             throw new SecurityException("notifyStagedApkSession may only be called by the system.");
         }
         getHandler().post(() -> {
-            RollbackData rd = null;
+            Rollback rollback = null;
             synchronized (mLock) {
-                ensureRollbackDataLoadedLocked();
                 for (int i = 0; i < mRollbacks.size(); ++i) {
-                    RollbackData data = mRollbacks.get(i);
-                    if (data.stagedSessionId == originalSessionId) {
-                        data.apkSessionId = apkSessionId;
-                        rd = data;
+                    Rollback candidate = mRollbacks.get(i);
+                    if (candidate.stagedSessionId == originalSessionId) {
+                        candidate.apkSessionId = apkSessionId;
+                        rollback = candidate;
                         break;
                     }
                 }
             }
 
-            if (rd != null) {
-                saveRollbackData(rd);
+            if (rollback != null) {
+                saveRollback(rollback);
             }
         });
     }
@@ -1289,7 +1205,8 @@
 
 
     private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
-        return a.getPackageName().equals(b.getPackageName())
+        return a != null && b != null
+            && a.getPackageName().equals(b.getPackageName())
             && a.getLongVersionCode() == b.getLongVersionCode();
     }
 
@@ -1318,7 +1235,7 @@
             }
 
             if (newRollback != null) {
-                RollbackData rollback = completeEnableRollback(newRollback, success);
+                Rollback rollback = completeEnableRollback(newRollback, success);
                 if (rollback != null && !rollback.isStaged()) {
                     makeRollbackAvailable(rollback);
                 }
@@ -1331,32 +1248,32 @@
      * This should be called after rollback has been enabled for all packages
      * in the rollback. It does not make the rollback available yet.
      *
-     * @return the rollback data for a successfully enable-completed rollback,
+     * @return the Rollback instance for a successfully enable-completed rollback,
      * or null on error.
      */
-    private RollbackData completeEnableRollback(NewRollback newRollback, boolean success) {
-        RollbackData data = newRollback.data;
+    private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
+        Rollback rollback = newRollback.rollback;
         if (!success) {
             // The install session was aborted, clean up the pending install.
-            deleteRollback(data);
+            deleteRollback(rollback);
             return null;
         }
         if (newRollback.isCancelled) {
-            Log.e(TAG, "Rollback has been cancelled by PackageManager");
-            deleteRollback(data);
+            Slog.e(TAG, "Rollback has been cancelled by PackageManager");
+            deleteRollback(rollback);
             return null;
         }
 
-        // It's safe to access data.info outside a synchronized block because
+        // It's safe to access rollback.info outside a synchronized block because
         // this is running on the handler thread and all changes to the
-        // data.info occur on the handler thread.
-        if (data.info.getPackages().size() != newRollback.packageSessionIds.length) {
-            Log.e(TAG, "Failed to enable rollback for all packages in session.");
-            deleteRollback(data);
+        // rollback.info occur on the handler thread.
+        if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) {
+            Slog.e(TAG, "Failed to enable rollback for all packages in session.");
+            deleteRollback(rollback);
             return null;
         }
 
-        saveRollbackData(data);
+        saveRollback(rollback);
         synchronized (mLock) {
             // Note: There is a small window of time between when
             // the session has been committed by the package
@@ -1364,26 +1281,25 @@
             // here. Presumably the window is small enough that
             // nobody will want to roll back the newly installed
             // package before we make the rollback available.
-            // TODO: We'll lose the rollback data if the
+            // TODO: We'll lose the rollback if the
             // device reboots between when the session is
             // committed and this point. Revisit this after
             // adding support for rollback of staged installs.
-            ensureRollbackDataLoadedLocked();
-            mRollbacks.add(data);
+            mRollbacks.add(rollback);
         }
 
-        return data;
+        return rollback;
     }
 
-    private void makeRollbackAvailable(RollbackData data) {
+    private void makeRollbackAvailable(Rollback rollback) {
         // TODO: What if the rollback has since been expired, for example due
         // to a new package being installed. Won't this revive an expired
         // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this.
         synchronized (mLock) {
-            data.state = RollbackData.ROLLBACK_STATE_AVAILABLE;
-            data.timestamp = Instant.now();
+            rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE;
+            rollback.timestamp = Instant.now();
         }
-        saveRollbackData(data);
+        saveRollback(rollback);
 
         // TODO(zezeozue): Provide API to explicitly start observing instead
         // of doing this for all rollbacks. If we do this for all rollbacks,
@@ -1391,8 +1307,8 @@
         // After enabling and commiting any rollback, observe packages and
         // prepare to rollback if packages crashes too frequently.
         List<String> packages = new ArrayList<>();
-        for (int i = 0; i < data.info.getPackages().size(); i++) {
-            packages.add(data.info.getPackages().get(i).getPackageName());
+        for (int i = 0; i < rollback.info.getPackages().size(); i++) {
+            packages.add(rollback.info.getPackages().get(i).getPackageName());
         }
         mPackageHealthObserver.startObservingHealth(packages,
                 mRollbackLifetimeDurationInMillis);
@@ -1400,18 +1316,14 @@
     }
 
     /*
-     * Returns the RollbackData, if any, for a rollback with the given
-     * rollbackId.
+     * Returns the rollback with the given rollbackId, if any.
      */
-    private RollbackData getRollbackForId(int rollbackId) {
+    private Rollback getRollbackForId(int rollbackId) {
         synchronized (mLock) {
-            // TODO: Have ensureRollbackDataLoadedLocked return the list of
-            // available rollbacks, to hopefully avoid forgetting to call it?
-            ensureRollbackDataLoadedLocked();
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                RollbackData data = mRollbacks.get(i);
-                if (data.info.getRollbackId() == rollbackId) {
-                    return data;
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.info.getRollbackId() == rollbackId) {
+                    return rollback;
                 }
             }
         }
@@ -1421,11 +1333,11 @@
 
     /**
      * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
-     * a specified {@code RollbackData}.
+     * a specified {@code Rollback}.
      */
-    private static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
+    private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback,
             String packageName) {
-        for (PackageRollbackInfo info : data.info.getPackages()) {
+        for (PackageRollbackInfo info : rollback.info.getPackages()) {
             if (info.getPackageName().equals(packageName)) {
                 return info;
             }
@@ -1449,30 +1361,30 @@
         throw new IllegalStateException("Failed to allocate rollback ID");
     }
 
-    private void deleteRollback(RollbackData rollbackData) {
-        for (PackageRollbackInfo info : rollbackData.info.getPackages()) {
-            IntArray installedUsers = info.getInstalledUsers();
-            for (int i = 0; i < installedUsers.size(); i++) {
-                int userId = installedUsers.get(i);
-                mAppDataRollbackHelper.destroyAppDataSnapshot(rollbackData.info.getRollbackId(),
+    private void deleteRollback(Rollback rollback) {
+        for (PackageRollbackInfo info : rollback.info.getPackages()) {
+            IntArray snapshottedUsers = info.getSnapshottedUsers();
+            for (int i = 0; i < snapshottedUsers.size(); i++) {
+                int userId = snapshottedUsers.get(i);
+                mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(),
                         info, userId);
             }
         }
-        mRollbackStore.deleteRollbackData(rollbackData);
+        mRollbackStore.deleteRollback(rollback);
     }
 
     /**
-     * Saves rollback data, swallowing any IOExceptions.
+     * Saves a rollback, swallowing any IOExceptions.
      * For those times when it's not obvious what to do about the IOException.
      * TODO: Double check we can't do a better job handling the IOException in
      * a cases where this method is called.
      */
-    private void saveRollbackData(RollbackData rollbackData) {
+    private void saveRollback(Rollback rollback) {
         try {
-            mRollbackStore.saveRollbackData(rollbackData);
+            mRollbackStore.saveRollback(rollback);
         } catch (IOException ioe) {
-            Log.e(TAG, "Unable to save rollback info for: "
-                    + rollbackData.info.getRollbackId(), ioe);
+            Slog.e(TAG, "Unable to save rollback for: "
+                    + rollback.info.getRollbackId(), ioe);
         }
     }
 
@@ -1480,14 +1392,14 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         synchronized (mLock) {
-            for (RollbackData data : mRollbacks) {
-                RollbackInfo info = data.info;
+            for (Rollback rollback : mRollbacks) {
+                RollbackInfo info = rollback.info;
                 ipw.println(info.getRollbackId() + ":");
                 ipw.increaseIndent();
-                ipw.println("-state: " + data.getStateAsString());
-                ipw.println("-timestamp: " + data.timestamp);
-                if (data.stagedSessionId != -1) {
-                    ipw.println("-stagedSessionId: " + data.stagedSessionId);
+                ipw.println("-state: " + rollback.getStateAsString());
+                ipw.println("-timestamp: " + rollback.timestamp);
+                if (rollback.stagedSessionId != -1) {
+                    ipw.println("-stagedSessionId: " + rollback.stagedSessionId);
                 }
                 ipw.println("-packages:");
                 ipw.increaseIndent();
@@ -1497,7 +1409,7 @@
                             + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
                 }
                 ipw.decreaseIndent();
-                if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
+                if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) {
                     ipw.println("-causePackages:");
                     ipw.increaseIndent();
                     for (VersionedPackage cPkg : info.getCausePackages()) {
@@ -1523,7 +1435,7 @@
     }
 
     private static class NewRollback {
-        public final RollbackData data;
+        public final Rollback rollback;
 
         /**
          * This array holds all of the rollback tokens associated with package sessions included
@@ -1541,9 +1453,9 @@
         public final int[] packageSessionIds;
 
         /**
-         * Flag to determine whether the RollbackData has been cancelled.
+         * Flag to determine whether the rollback has been cancelled.
          *
-         * <p>RollbackData could be invalidated and cancelled if RollbackManager receives
+         * <p>Rollback could be invalidated and cancelled if RollbackManager receives
          * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} from {@link PackageManager}.
          *
          * <p>The main underlying assumption here is that if enabling the rollback times out, then
@@ -1553,8 +1465,8 @@
          */
         public boolean isCancelled = false;
 
-        NewRollback(RollbackData data, int[] packageSessionIds) {
-            this.data = data;
+        NewRollback(Rollback rollback, int[] packageSessionIds) {
+            this.rollback = rollback;
             this.packageSessionIds = packageSessionIds;
         }
 
@@ -1569,13 +1481,13 @@
 
     NewRollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
         int rollbackId = allocateRollbackIdLocked();
-        final RollbackData data;
+        final Rollback rollback;
         int parentSessionId = parentSession.getSessionId();
 
         if (parentSession.isStaged()) {
-            data = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
+            rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId);
         } else {
-            data = mRollbackStore.createNonStagedRollback(rollbackId);
+            rollback = mRollbackStore.createNonStagedRollback(rollbackId);
         }
 
         int[] packageSessionIds;
@@ -1585,7 +1497,7 @@
             packageSessionIds = new int[]{parentSessionId};
         }
 
-        return new NewRollback(data, packageSessionIds);
+        return new NewRollback(rollback, packageSessionIds);
     }
 
     /**
@@ -1596,10 +1508,10 @@
     NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
         // We expect mNewRollbacks to be a very small list; linear search
         // should be plenty fast.
-        for (NewRollback newRollbackData : mNewRollbacks) {
-            for (int id : newRollbackData.packageSessionIds) {
+        for (NewRollback newRollback: mNewRollbacks) {
+            for (int id : newRollback.packageSessionIds) {
                 if (id == packageSessionId) {
-                    return newRollbackData;
+                    return newRollback;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 8a26368c..b2448f6 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -16,8 +16,8 @@
 
 package com.android.server.rollback;
 
-import static com.android.server.rollback.RollbackData.rollbackStateFromString;
-import static com.android.server.rollback.RollbackData.rollbackStateToString;
+import static com.android.server.rollback.Rollback.rollbackStateFromString;
+import static com.android.server.rollback.Rollback.rollbackStateToString;
 
 import android.annotation.NonNull;
 import android.content.pm.VersionedPackage;
@@ -25,7 +25,7 @@
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.content.rollback.RollbackInfo;
 import android.util.IntArray;
-import android.util.Log;
+import android.util.Slog;
 import android.util.SparseLongArray;
 
 import libcore.io.IoUtils;
@@ -73,17 +73,17 @@
     }
 
     /**
-     * Reads the rollback data from persistent storage.
+     * Reads the rollbacks from persistent storage.
      */
-    List<RollbackData> loadAllRollbackData() {
-        List<RollbackData> rollbacks = new ArrayList<>();
+    List<Rollback> loadRollbacks() {
+        List<Rollback> rollbacks = new ArrayList<>();
         mRollbackDataDir.mkdirs();
         for (File rollbackDir : mRollbackDataDir.listFiles()) {
             if (rollbackDir.isDirectory()) {
                 try {
-                    rollbacks.add(loadRollbackData(rollbackDir));
+                    rollbacks.add(loadRollback(rollbackDir));
                 } catch (IOException e) {
-                    Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+                    Slog.e(TAG, "Unable to read rollback at " + rollbackDir, e);
                     removeFile(rollbackDir);
                 }
             }
@@ -191,21 +191,21 @@
     }
 
     /**
-     * Creates a new RollbackData instance for a non-staged rollback with
+     * Creates a new Rollback instance for a non-staged rollback with
      * backupDir assigned.
      */
-    RollbackData createNonStagedRollback(int rollbackId) {
+    Rollback createNonStagedRollback(int rollbackId) {
         File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
-        return new RollbackData(rollbackId, backupDir, -1);
+        return new Rollback(rollbackId, backupDir, -1);
     }
 
     /**
-     * Creates a new RollbackData instance for a staged rollback with
+     * Creates a new Rollback instance for a staged rollback with
      * backupDir assigned.
      */
-    RollbackData createStagedRollback(int rollbackId, int stagedSessionId) {
+    Rollback createStagedRollback(int rollbackId, int stagedSessionId) {
         File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
-        return new RollbackData(rollbackId, backupDir, stagedSessionId);
+        return new Rollback(rollbackId, backupDir, stagedSessionId);
     }
 
     /**
@@ -213,10 +213,10 @@
      * For packages containing splits, this method should be called for each
      * of the package's split apks in addition to the base apk.
      */
-    static void backupPackageCodePath(RollbackData data, String packageName, String codePath)
+    static void backupPackageCodePath(Rollback rollback, String packageName, String codePath)
             throws IOException {
         File sourceFile = new File(codePath);
-        File targetDir = new File(data.backupDir, packageName);
+        File targetDir = new File(rollback.backupDir, packageName);
         targetDir.mkdirs();
         File targetFile = new File(targetDir, sourceFile.getName());
 
@@ -228,8 +228,8 @@
      * Returns the apk or apex files backed up for the given package.
      * Includes the base apk and any splits. Returns null if none found.
      */
-    static File[] getPackageCodePaths(RollbackData data, String packageName) {
-        File targetDir = new File(data.backupDir, packageName);
+    static File[] getPackageCodePaths(Rollback rollback, String packageName) {
+        File targetDir = new File(rollback.backupDir, packageName);
         File[] files = targetDir.listFiles();
         if (files == null || files.length == 0) {
             return null;
@@ -241,27 +241,27 @@
      * Deletes all backed up apks and apex files associated with the given
      * rollback.
      */
-    static void deletePackageCodePaths(RollbackData data) {
-        for (PackageRollbackInfo info : data.info.getPackages()) {
-            File targetDir = new File(data.backupDir, info.getPackageName());
+    static void deletePackageCodePaths(Rollback rollback) {
+        for (PackageRollbackInfo info : rollback.info.getPackages()) {
+            File targetDir = new File(rollback.backupDir, info.getPackageName());
             removeFile(targetDir);
         }
     }
 
     /**
-     * Saves the rollback data to persistent storage.
+     * Saves the given rollback to persistent storage.
      */
-    void saveRollbackData(RollbackData data) throws IOException {
+    void saveRollback(Rollback rollback) throws IOException {
         try {
             JSONObject dataJson = new JSONObject();
-            dataJson.put("info", rollbackInfoToJson(data.info));
-            dataJson.put("timestamp", data.timestamp.toString());
-            dataJson.put("stagedSessionId", data.stagedSessionId);
-            dataJson.put("state", rollbackStateToString(data.state));
-            dataJson.put("apkSessionId", data.apkSessionId);
-            dataJson.put("restoreUserDataInProgress", data.restoreUserDataInProgress);
+            dataJson.put("info", rollbackInfoToJson(rollback.info));
+            dataJson.put("timestamp", rollback.timestamp.toString());
+            dataJson.put("stagedSessionId", rollback.stagedSessionId);
+            dataJson.put("state", rollbackStateToString(rollback.state));
+            dataJson.put("apkSessionId", rollback.apkSessionId);
+            dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress);
 
-            PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
+            PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json"));
             pw.println(dataJson.toString());
             pw.close();
         } catch (JSONException e) {
@@ -270,23 +270,23 @@
     }
 
     /**
-     * Removes all persistant storage associated with the given rollback data.
+     * Removes all persistent storage associated with the given rollback.
      */
-    void deleteRollbackData(RollbackData data) {
-        removeFile(data.backupDir);
+    void deleteRollback(Rollback rollback) {
+        removeFile(rollback.backupDir);
     }
 
     /**
      * Reads the metadata for a rollback from the given directory.
      * @throws IOException in case of error reading the data.
      */
-    private static RollbackData loadRollbackData(File backupDir) throws IOException {
+    private static Rollback loadRollback(File backupDir) throws IOException {
         try {
             File rollbackJsonFile = new File(backupDir, "rollback.json");
             JSONObject dataJson = new JSONObject(
                     IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath()));
 
-            return new RollbackData(
+            return new Rollback(
                     rollbackInfoFromJson(dataJson.getJSONObject("info")),
                     backupDir,
                     Instant.parse(dataJson.getString("timestamp")),
@@ -319,13 +319,14 @@
 
         IntArray pendingBackups = info.getPendingBackups();
         List<RestoreInfo> pendingRestores = info.getPendingRestores();
-        IntArray installedUsers = info.getInstalledUsers();
+        IntArray snapshottedUsers = info.getSnapshottedUsers();
         json.put("pendingBackups", convertToJsonArray(pendingBackups));
         json.put("pendingRestores", convertToJsonArray(pendingRestores));
 
         json.put("isApex", info.isApex());
 
-        json.put("installedUsers", convertToJsonArray(installedUsers));
+        // Field is named 'installedUsers' for legacy reasons.
+        json.put("installedUsers", convertToJsonArray(snapshottedUsers));
         json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
 
         return json;
@@ -345,12 +346,13 @@
 
         final boolean isApex = json.getBoolean("isApex");
 
-        final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
+        // Field is named 'installedUsers' for legacy reasons.
+        final IntArray snapshottedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
         final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
                 json.getJSONArray("ceSnapshotInodes"));
 
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
-                pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes);
+                pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes);
     }
 
     private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
index 8c7b5ac..2cc931b 100644
--- a/services/core/java/com/android/server/rollback/TEST_MAPPING
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -1,12 +1,6 @@
 {
   "presubmit": [
     {
-      "name": "RollbackTest"
-    },
-    {
-      "name": "StagedRollbackTest"
-    },
-    {
       "name": "FrameworksServicesTests",
       "options": [
         {
@@ -21,6 +15,9 @@
     },
     {
       "path": "cts/hostsidetests/rollback"
+    },
+    {
+      "path": "frameworks/base/tests/RollbackTest"
     }
   ]
 }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6175d41..7b3fbb9 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -130,7 +130,6 @@
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
-        "android.hardware.vibrator@1.4",
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 3726228..746610d 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "VibratorService"
 
-#include <android/hardware/vibrator/1.4/IVibrator.h>
+#include <android/hardware/vibrator/1.3/IVibrator.h>
 #include <android/hardware/vibrator/BnVibratorCallback.h>
 #include <android/hardware/vibrator/IVibrator.h>
 #include <binder/IServiceManager.h>
@@ -43,166 +43,41 @@
 namespace V1_1 = android::hardware::vibrator::V1_1;
 namespace V1_2 = android::hardware::vibrator::V1_2;
 namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace V1_4 = android::hardware::vibrator::V1_4;
 namespace aidl = android::hardware::vibrator;
 
 namespace android {
 
 static jmethodID sMethodIdOnComplete;
 
-// TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove
-// shim
-class VibratorShim : public V1_4::IVibrator {
-  public:
-    VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {}
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+                static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+                static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+                static_cast<uint8_t>(aidl::EffectStrength::STRONG));
 
-    Return<V1_0::Status> on(uint32_t timeoutMs) override {
-        return on_1_4(timeoutMs, nullptr);
-    }
+static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+                static_cast<uint8_t>(aidl::Effect::CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+                static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
+                static_cast<uint8_t>(aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
+                static_cast<uint8_t>(aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
+                static_cast<uint8_t>(aidl::Effect::POP));
+static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+                static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+                static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+                static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+                static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+                static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
 
-    Return<V1_0::Status> off() override {
-        return toHidlStatus(mVib->off());
-    }
-
-    Return<bool> supportsAmplitudeControl() override {
-        int32_t cap = 0;
-        if (!mVib->getCapabilities(&cap).isOk()) return false;
-        if (mUnderExternalControl) {
-           return (cap & aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
-        } else {
-           return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
-        }
-    }
-
-    Return<V1_0::Status> setAmplitude(uint8_t amplitude) override {
-        return toHidlStatus(mVib->setAmplitude(amplitude));
-    }
-
-    Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength,
-                         perform_cb _hidl_cb) override {
-        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
-    }
-
-    Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength,
-                             perform_1_1_cb _hidl_cb) override {
-        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
-    }
-
-    Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength,
-                             perform_1_2_cb _hidl_cb) override {
-        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
-    }
-
-    Return<bool> supportsExternalControl() override {
-        int32_t cap = 0;
-        if (!mVib->getCapabilities(&cap).isOk()) return false;
-        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
-    }
-
-    Return<V1_0::Status> setExternalControl(bool enabled) override {
-        Return<V1_0::Status> status = toHidlStatus(mVib->setExternalControl(enabled));
-        if (status.isOk() && status == V1_0::Status::OK) {
-            mUnderExternalControl = enabled;
-        }
-        return status;
-    }
-
-    Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength,
-                             perform_1_3_cb _hidl_cb) override {
-        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
-    }
-
-    Return<uint32_t> getCapabilities() override {
-        static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) ==
-                      static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK));
-        static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) ==
-                      static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK));
-
-        int32_t cap;
-        if (!mVib->getCapabilities(&cap).isOk()) return 0;
-        return (cap & (aidl::IVibrator::CAP_ON_CALLBACK |
-                       aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0;
-    }
-
-    Return<V1_0::Status> on_1_4(uint32_t timeoutMs,
-                                const sp<V1_4::IVibratorCallback>& callback) override {
-        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
-        return toHidlStatus(mVib->on(timeoutMs, cb));
-    }
-
-    Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength,
-                             const sp<V1_4::IVibratorCallback>& callback,
-                             perform_1_4_cb _hidl_cb) override {
-        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
-                      static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
-        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
-                      static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
-        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
-                      static_cast<uint8_t>(aidl::EffectStrength::STRONG));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
-                      static_cast<uint8_t>(aidl::Effect::CLICK));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
-                      static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
-                      static_cast<uint8_t>(aidl::Effect::TICK));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
-                      static_cast<uint8_t>(aidl::Effect::THUD));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
-                      static_cast<uint8_t>(aidl::Effect::POP));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
-                      static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
-                      static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
-                      static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
-                      static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
-        static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
-                      static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-
-        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
-        int timeoutMs = 0;
-        Return<V1_0::Status> status = toHidlStatus(
-            mVib->perform(static_cast<aidl::Effect>(effect),
-                          static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs));
-
-        if (status.isOk()) {
-            _hidl_cb(status, timeoutMs);
-            return android::hardware::Status::ok();
-        } else {
-            return android::hardware::details::StatusOf<V1_0::Status, void>(status);
-        }
-    }
-  private:
-    sp<aidl::IVibrator> mVib;
-    bool mUnderExternalControl = false;
-
-    Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) {
-        switch(status.exceptionCode()) {
-            using android::hardware::Status;
-            case Status::EX_NONE: return V1_0::Status::OK;
-            case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE;
-            case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION;
-            case Status::EX_TRANSACTION_FAILED: {
-                return Status::fromStatusT(status.transactionError());
-            }
-        }
-        return V1_0::Status::UNKNOWN_ERROR;
-    }
-
-    class CallbackShim : public aidl::BnVibratorCallback {
-      public:
-        CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {}
-        binder::Status onComplete() {
-            mCb->onComplete();
-            return binder::Status::ok(); // oneway, local call
-        }
-      private:
-        sp<V1_4::IVibratorCallback> mCb;
-    };
-};
-
-class VibratorCallback : public V1_4::IVibratorCallback {
+class VibratorCallback {
     public:
         VibratorCallback(JNIEnv *env, jobject vibration) :
         mVibration(MakeGlobalRefOrDie(env, vibration)) {}
@@ -212,47 +87,92 @@
             env->DeleteGlobalRef(mVibration);
         }
 
-        Return<void> onComplete() override {
+        void onComplete() {
             auto env = AndroidRuntime::getJNIEnv();
             env->CallVoidMethod(mVibration, sMethodIdOnComplete);
-            return Void();
         }
 
     private:
         jobject mVibration;
 };
 
+class AidlVibratorCallback : public aidl::BnVibratorCallback {
+  public:
+    AidlVibratorCallback(JNIEnv *env, jobject vibration) :
+    mCb(env, vibration) {}
+
+    binder::Status onComplete() override {
+        mCb.onComplete();
+        return binder::Status::ok(); // oneway, local call
+    }
+
+  private:
+    VibratorCallback mCb;
+};
+
 static constexpr int NUM_TRIES = 2;
 
+template<class R>
+inline R NoneStatus() {
+    using ::android::hardware::Status;
+    return Status::fromExceptionCode(Status::EX_NONE);
+}
+
+template<>
+inline binder::Status NoneStatus() {
+    using binder::Status;
+    return Status::fromExceptionCode(Status::EX_NONE);
+}
+
 // Creates a Return<R> with STATUS::EX_NULL_POINTER.
 template<class R>
-inline Return<R> NullptrStatus() {
+inline R NullptrStatus() {
     using ::android::hardware::Status;
-    return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
+    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template<>
+inline binder::Status NullptrStatus() {
+    using binder::Status;
+    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+}
+
+template <typename I>
+sp<I> getService() {
+    return I::getService();
+}
+
+template <>
+sp<aidl::IVibrator> getService() {
+    return waitForVintfService<aidl::IVibrator>();
+}
+
+template <typename I>
+sp<I> tryGetService() {
+    return I::tryGetService();
+}
+
+template <>
+sp<aidl::IVibrator> tryGetService() {
+    return checkVintfService<aidl::IVibrator>();
 }
 
 template <typename I>
 class HalWrapper {
   public:
     static std::unique_ptr<HalWrapper> Create() {
-        sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>();
-        if (aidlVib) {
-            return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib)));
-        }
-
         // Assume that if getService returns a nullptr, HAL is not available on the
         // device.
-        auto hal = I::getService();
+        auto hal = getService<I>();
         return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
     }
 
     // Helper used to transparently deal with the vibrator HAL becoming unavailable.
     template<class R, class... Args0, class... Args1>
-    Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+    R call(R (I::* fn)(Args0...), Args1&&... args1) {
         // Return<R> doesn't have a default constructor, so make a Return<R> with
         // STATUS::EX_NONE.
-        using ::android::hardware::Status;
-        Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};
+        R ret{NoneStatus<R>()};
 
         // Note that ret is guaranteed to be changed after this loop.
         for (int i = 0; i < NUM_TRIES; ++i) {
@@ -266,12 +186,7 @@
             ALOGE("Failed to issue command to vibrator HAL. Retrying.");
 
             // Restoring connection to the HAL.
-            sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>();
-            if (aidlVib) {
-                mHal = new VibratorShim(aidlVib);
-            } else {
-                mHal = I::tryGetService();
-            }
+            mHal = tryGetService<I>();
         }
         return ret;
     }
@@ -290,7 +205,7 @@
 }
 
 template<class R, class I, class... Args0, class... Args1>
-Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+R halCall(R (I::* fn)(Args0...), Args1&&... args1) {
     auto hal = getHal<I>();
     return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
 }
@@ -307,110 +222,192 @@
 
 static void vibratorInit(JNIEnv *env, jclass clazz)
 {
-    halCall(&V1_0::IVibrator::ping).isOk();
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        // IBinder::pingBinder isn't accessible as a pointer function
+        // but getCapabilities can serve the same purpose
+        int32_t cap;
+        hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
+    } else {
+        halCall(&V1_0::IVibrator::ping).isOk();
+    }
 }
 
 static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
 {
-    return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
+    bool ok;
+
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        // IBinder::pingBinder isn't accessible as a pointer function
+        // but getCapabilities can serve the same purpose
+        int32_t cap;
+        ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
+    } else {
+        ok = halCall(&V1_0::IVibrator::ping).isOk();
+    }
+    return ok ? JNI_TRUE : JNI_FALSE;
 }
 
 static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
 {
-    Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
-    if (retStatus != Status::OK) {
-        ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
+        if (!status.isOk()) {
+            ALOGE("vibratorOn command failed: %s", status.toString8().string());
+        }
+    } else {
+        Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
+        if (retStatus != Status::OK) {
+            ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+        }
     }
 }
 
 static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
 {
-    Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
-    if (retStatus != Status::OK) {
-        ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        auto status = hal->call(&aidl::IVibrator::off);
+        if (!status.isOk()) {
+            ALOGE("vibratorOff command failed: %s", status.toString8().string());
+        }
+    } else {
+        Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
+        if (retStatus != Status::OK) {
+            ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
+        }
     }
 }
 
 static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
-    return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        int32_t cap = 0;
+        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+            return false;
+        }
+        return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
+    } else {
+        return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+    }
 }
 
 static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
-    Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
-        .withDefault(Status::UNKNOWN_ERROR);
-    if (status != Status::OK) {
-      ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
-            static_cast<uint32_t>(status));
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude);
+        if (!status.isOk()) {
+            ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
+        }
+    } else {
+        Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
+            .withDefault(Status::UNKNOWN_ERROR);
+        if (status != Status::OK) {
+            ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
+                  static_cast<uint32_t>(status));
+        }
     }
 }
 
 static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
-    return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        int32_t cap = 0;
+        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+            return false;
+        }
+        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
+    } else {
+        return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+    }
 }
 
 static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
-    Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
-        .withDefault(Status::UNKNOWN_ERROR);
-    if (status != Status::OK) {
-      ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
-            static_cast<uint32_t>(status));
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
+        if (!status.isOk()) {
+            ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
+        }
+    } else {
+        Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
+            .withDefault(Status::UNKNOWN_ERROR);
+        if (status != Status::OK) {
+            ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
+                static_cast<uint32_t>(status));
+        }
     }
 }
 
 static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
                                    jobject vibration) {
-    Status status;
-    uint32_t lengthMs;
-    auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
-        status = retStatus;
-        lengthMs = retLengthMs;
-    };
-    EffectStrength effectStrength(static_cast<EffectStrength>(strength));
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        int32_t lengthMs;
+        sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
+        aidl::Effect effectType(static_cast<aidl::Effect>(strength));
+        aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
 
-    Return<void> ret;
-    if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) {
-        sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration);
-        ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect),
-                effectStrength, effectCallback, callback);
-    } else if (isValidEffect<V1_0::Effect>(effect)) {
-        ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
-                effectStrength, callback);
-    } else if (isValidEffect<Effect_1_1>(effect)) {
-        ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
-                           effectStrength, callback);
-    } else if (isValidEffect<V1_2::Effect>(effect)) {
-        ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
-                           effectStrength, callback);
-    } else if (isValidEffect<V1_3::Effect>(effect)) {
-        ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
-                           effectStrength, callback);
-    } else {
-        ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
-                static_cast<int32_t>(effect));
-        return -1;
-    }
-
-    if (!ret.isOk()) {
-        ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
-        return -1;
-    }
-
-    if (status == Status::OK) {
+        auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
+        if (!status.isOk()) {
+            if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) {
+                ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
+                        ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string());
+            }
+            return -1;
+        }
         return lengthMs;
-    } else if (status != Status::UNSUPPORTED_OPERATION) {
-        // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
-        // doesn't have a pre-defined waveform to perform for it, so we should just give the
-        // opportunity to fall back to the framework waveforms.
-        ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
-                ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
-                static_cast<int32_t>(strength), static_cast<uint32_t>(status));
+    } else {
+        Status status;
+        uint32_t lengthMs;
+        auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
+            status = retStatus;
+            lengthMs = retLengthMs;
+        };
+        EffectStrength effectStrength(static_cast<EffectStrength>(strength));
+
+        Return<void> ret;
+        if (isValidEffect<V1_0::Effect>(effect)) {
+            ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
+                    effectStrength, callback);
+        } else if (isValidEffect<Effect_1_1>(effect)) {
+            ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
+                            effectStrength, callback);
+        } else if (isValidEffect<V1_2::Effect>(effect)) {
+            ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
+                            effectStrength, callback);
+        } else if (isValidEffect<V1_3::Effect>(effect)) {
+            ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
+                            effectStrength, callback);
+        } else {
+            ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
+                    static_cast<int32_t>(effect));
+            return -1;
+        }
+
+        if (!ret.isOk()) {
+            ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
+            return -1;
+        }
+
+        if (status == Status::OK) {
+            return lengthMs;
+        } else if (status != Status::UNSUPPORTED_OPERATION) {
+            // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
+            // doesn't have a pre-defined waveform to perform for it, so we should just give the
+            // opportunity to fall back to the framework waveforms.
+            ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
+                    ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
+                    static_cast<int32_t>(strength), static_cast<uint32_t>(status));
+        }
     }
 
     return -1;
 }
 
 static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
-    return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0);
+    if (auto hal = getHal<aidl::IVibrator>()) {
+        int32_t cap = 0;
+        if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
+            return 0;
+        }
+        return cap;
+    }
+
+    return 0;
 }
 
 static const JNINativeMethod method_table[] = {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 16c60ca..313f884 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -135,6 +135,7 @@
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.power.ThermalManagerService;
+import com.android.server.recoverysystem.RecoverySystemService;
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.role.RoleManagerService;
 import com.android.server.rollback.RollbackManagerService;
@@ -698,7 +699,7 @@
 
         // Bring up recovery system in case a rescue party needs a reboot
         traceBeginAndSlog("StartRecoverySystemService");
-        mSystemServiceManager.startService(RecoverySystemService.class);
+        mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
         traceEnd();
 
         // Now that we have the bare essentials of the OS up and running, take
diff --git a/services/net/Android.bp b/services/net/Android.bp
index c56ecd6..45430ea 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,38 +1,26 @@
 java_library_static {
     name: "services.net",
     srcs: [
+        ":net-module-utils-srcs",
         ":tethering-servicesnet-srcs",
         "java/**/*.java",
     ],
     static_libs: [
         "dnsresolver_aidl_interface-V2-java",
         "netd_aidl_interface-unstable-java",
+        "netlink-client",
         "networkstack-client",
         "tethering-client",
     ],
 }
 
 filegroup {
-    name: "services-networkstack-shared-srcs",
-    srcs: [
-        "java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering
-        "java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer
-        "java/android/net/shared/*.java",
-        "java/android/net/netlink/*.java",
-    ],
-}
-
-filegroup {
     name: "services-tethering-shared-srcs",
     srcs: [
         ":framework-annotations",
         "java/android/net/ConnectivityModuleConnector.java",
         "java/android/net/NetworkStackClient.java",
-        "java/android/net/ip/InterfaceController.java",
-        "java/android/net/netlink/*.java",
-        "java/android/net/util/InterfaceParams.java",
         "java/android/net/util/NetdService.java",
         "java/android/net/util/NetworkConstants.java",
-        "java/android/net/util/SharedLog.java"
     ],
 }
diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java
deleted file mode 100644
index 970bc9c..0000000
--- a/services/net/java/android/net/ip/InterfaceController.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import android.net.INetd;
-import android.net.InterfaceConfigurationParcel;
-import android.net.LinkAddress;
-import android.net.util.SharedLog;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.OsConstants;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-
-/**
- * Encapsulates the multiple IP configuration operations performed on an interface.
- *
- * TODO: refactor/eliminate the redundant ways to set and clear addresses.
- *
- * @hide
- */
-public class InterfaceController {
-    private final static boolean DBG = false;
-
-    private final String mIfName;
-    private final INetd mNetd;
-    private final SharedLog mLog;
-
-    public InterfaceController(String ifname, INetd netd, SharedLog log) {
-        mIfName = ifname;
-        mNetd = netd;
-        mLog = log;
-    }
-
-    private boolean setInterfaceAddress(LinkAddress addr) {
-        final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
-        ifConfig.ifName = mIfName;
-        ifConfig.ipv4Addr = addr.getAddress().getHostAddress();
-        ifConfig.prefixLength = addr.getPrefixLength();
-        ifConfig.hwAddr = "";
-        ifConfig.flags = new String[0];
-        try {
-            mNetd.interfaceSetCfg(ifConfig);
-        } catch (RemoteException | ServiceSpecificException e) {
-            logError("Setting IPv4 address to %s/%d failed: %s",
-                    ifConfig.ipv4Addr, ifConfig.prefixLength, e);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Set the IPv4 address of the interface.
-     */
-    public boolean setIPv4Address(LinkAddress address) {
-        if (!(address.getAddress() instanceof Inet4Address)) {
-            return false;
-        }
-        return setInterfaceAddress(address);
-    }
-
-    /**
-     * Clear the IPv4Address of the interface.
-     */
-    public boolean clearIPv4Address() {
-        return setInterfaceAddress(new LinkAddress("0.0.0.0/0"));
-    }
-
-    private boolean setEnableIPv6(boolean enabled) {
-        try {
-            mNetd.interfaceSetEnableIPv6(mIfName, enabled);
-        } catch (RemoteException | ServiceSpecificException e) {
-            logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Enable IPv6 on the interface.
-     */
-    public boolean enableIPv6() {
-        return setEnableIPv6(true);
-    }
-
-    /**
-     * Disable IPv6 on the interface.
-     */
-    public boolean disableIPv6() {
-        return setEnableIPv6(false);
-    }
-
-    /**
-     * Enable or disable IPv6 privacy extensions on the interface.
-     * @param enabled Whether the extensions should be enabled.
-     */
-    public boolean setIPv6PrivacyExtensions(boolean enabled) {
-        try {
-            mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
-        } catch (RemoteException | ServiceSpecificException e) {
-            logError("error %s IPv6 privacy extensions: %s",
-                    (enabled ? "enabling" : "disabling"), e);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Set IPv6 address generation mode on the interface.
-     *
-     * <p>IPv6 should be disabled before changing the mode.
-     */
-    public boolean setIPv6AddrGenModeIfSupported(int mode) {
-        try {
-            mNetd.setIPv6AddrGenMode(mIfName, mode);
-        } catch (RemoteException e) {
-            logError("Unable to set IPv6 addrgen mode: %s", e);
-            return false;
-        } catch (ServiceSpecificException e) {
-            if (e.errorCode != OsConstants.EOPNOTSUPP) {
-                logError("Unable to set IPv6 addrgen mode: %s", e);
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Add an address to the interface.
-     */
-    public boolean addAddress(LinkAddress addr) {
-        return addAddress(addr.getAddress(), addr.getPrefixLength());
-    }
-
-    /**
-     * Add an address to the interface.
-     */
-    public boolean addAddress(InetAddress ip, int prefixLen) {
-        try {
-            mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
-        } catch (ServiceSpecificException | RemoteException e) {
-            logError("failed to add %s/%d: %s", ip, prefixLen, e);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Remove an address from the interface.
-     */
-    public boolean removeAddress(InetAddress ip, int prefixLen) {
-        try {
-            mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
-        } catch (ServiceSpecificException | RemoteException e) {
-            logError("failed to remove %s/%d: %s", ip, prefixLen, e);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Remove all addresses from the interface.
-     */
-    public boolean clearAllAddresses() {
-        try {
-            mNetd.interfaceClearAddrs(mIfName);
-        } catch (Exception e) {
-            logError("Failed to clear addresses: %s", e);
-            return false;
-        }
-        return true;
-    }
-
-    private void logError(String fmt, Object... args) {
-        mLog.e(String.format(fmt, args));
-    }
-}
diff --git a/services/net/java/android/net/netlink/ConntrackMessage.java b/services/net/java/android/net/netlink/ConntrackMessage.java
deleted file mode 100644
index 6978739..0000000
--- a/services/net/java/android/net/netlink/ConntrackMessage.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import android.system.OsConstants;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * A NetlinkMessage subclass for netlink conntrack messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/netfilter/nfnetlink_conntrack.h
- *
- * @hide
- */
-public class ConntrackMessage extends NetlinkMessage {
-    public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
-
-    public static final short NFNL_SUBSYS_CTNETLINK = 1;
-    public static final short IPCTNL_MSG_CT_NEW = 0;
-
-    // enum ctattr_type
-    public static final short CTA_TUPLE_ORIG  = 1;
-    public static final short CTA_TUPLE_REPLY = 2;
-    public static final short CTA_TIMEOUT     = 7;
-
-    // enum ctattr_tuple
-    public static final short CTA_TUPLE_IP    = 1;
-    public static final short CTA_TUPLE_PROTO = 2;
-
-    // enum ctattr_ip
-    public static final short CTA_IP_V4_SRC = 1;
-    public static final short CTA_IP_V4_DST = 2;
-
-    // enum ctattr_l4proto
-    public static final short CTA_PROTO_NUM      = 1;
-    public static final short CTA_PROTO_SRC_PORT = 2;
-    public static final short CTA_PROTO_DST_PORT = 3;
-
-    public static byte[] newIPv4TimeoutUpdateRequest(
-            int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) {
-        // *** STYLE WARNING ***
-        //
-        // Code below this point uses extra block indentation to highlight the
-        // packing of nested tuple netlink attribute types.
-        final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG,
-                new StructNlAttr(CTA_TUPLE_IP,
-                        new StructNlAttr(CTA_IP_V4_SRC, src),
-                        new StructNlAttr(CTA_IP_V4_DST, dst)),
-                new StructNlAttr(CTA_TUPLE_PROTO,
-                        new StructNlAttr(CTA_PROTO_NUM, (byte) proto),
-                        new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN),
-                        new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN)));
-
-        final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN);
-
-        final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength();
-        final byte[] bytes = new byte[STRUCT_SIZE + payloadLength];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final ConntrackMessage ctmsg = new ConntrackMessage();
-        ctmsg.mHeader.nlmsg_len = bytes.length;
-        ctmsg.mHeader.nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
-        ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
-        ctmsg.mHeader.nlmsg_seq = 1;
-        ctmsg.pack(byteBuffer);
-
-        ctaTupleOrig.pack(byteBuffer);
-        ctaTimeout.pack(byteBuffer);
-
-        return bytes;
-    }
-
-    protected StructNfGenMsg mNfGenMsg;
-
-    private ConntrackMessage() {
-        super(new StructNlMsgHdr());
-        mNfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET);
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        mHeader.pack(byteBuffer);
-        mNfGenMsg.pack(byteBuffer);
-    }
-}
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
deleted file mode 100644
index ca07630..0000000
--- a/services/net/java/android/net/netlink/InetDiagMessage.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.NETLINK_INET_DIAG;
-
-import android.annotation.Nullable;
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * A NetlinkMessage subclass for netlink inet_diag messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * @hide
- */
-public class InetDiagMessage extends NetlinkMessage {
-    public static final String TAG = "InetDiagMessage";
-    private static final int TIMEOUT_MS = 500;
-
-    public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
-            InetSocketAddress remote, int family, short flags) {
-        return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
-                0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
-    }
-
-    /**
-     * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
-     * if local and remote are not both null or both non-null.
-     *
-     * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
-     *                 IPPROTO_UDP, or IPPROTO_UDPLITE.
-     * @param local local socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
-     *              local or remote address is null.
-     * @param remote remote socket address of the target socket. This will be packed into a
-     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
-     *              local or remote address is null.
-     * @param family the ip family of the request message. This should be set to either AF_INET or
-     *               AF_INET6 for IPv4 or IPv6 sockets respectively.
-     * @param flags message flags. See &lt;linux_src&gt;/include/uapi/linux/netlink.h.
-     * @param pad for raw socket protocol specification.
-     * @param idiagExt a set of flags defining what kind of extended information to report.
-     * @param state a bit mask that defines a filter of socket states.
-     *
-     * @return bytes array representation of the message
-     **/
-    public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
-            @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
-            int state) throws NullPointerException {
-        final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
-        nlMsgHdr.nlmsg_len = bytes.length;
-        nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
-        nlMsgHdr.nlmsg_flags = flags;
-        nlMsgHdr.pack(byteBuffer);
-        final StructInetDiagReqV2 inetDiagReqV2 =
-                new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
-
-        inetDiagReqV2.pack(byteBuffer);
-        return bytes;
-    }
-
-    public StructInetDiagMsg mStructInetDiagMsg;
-
-    private InetDiagMessage(StructNlMsgHdr header) {
-        super(header);
-        mStructInetDiagMsg = new StructInetDiagMsg();
-    }
-
-    public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final InetDiagMessage msg = new InetDiagMessage(header);
-        msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
-        return msg;
-    }
-
-    private static int lookupUidByFamily(int protocol, InetSocketAddress local,
-                                         InetSocketAddress remote, int family, short flags,
-                                         FileDescriptor fd)
-            throws ErrnoException, InterruptedIOException {
-        byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
-        NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
-        ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
-
-        final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
-        final StructNlMsgHdr hdr = nlMsg.getHeader();
-        if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
-            return INVALID_UID;
-        }
-        if (nlMsg instanceof InetDiagMessage) {
-            return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
-        }
-        return INVALID_UID;
-    }
-
-    private static final int FAMILY[] = {AF_INET6, AF_INET};
-
-    private static int lookupUid(int protocol, InetSocketAddress local,
-                                 InetSocketAddress remote, FileDescriptor fd)
-            throws ErrnoException, InterruptedIOException {
-        int uid;
-
-        for (int family : FAMILY) {
-            /**
-             * For exact match lookup, swap local and remote for UDP lookups due to kernel
-             * bug which will not be fixed. See aosp/755889 and
-             * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
-             */
-            if (protocol == IPPROTO_UDP) {
-                uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
-            } else {
-                uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
-            }
-            if (uid != INVALID_UID) {
-                return uid;
-            }
-        }
-
-        /**
-         * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
-         * socket is not connected (and even if the socket is connected to a different destination).
-         * If we want this API to work for such packets, then on miss we need to do a second lookup
-         * with only the local address and port filled in.
-         * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
-         */
-        if (protocol == IPPROTO_UDP) {
-            try {
-                InetSocketAddress wildcard = new InetSocketAddress(
-                        Inet6Address.getByName("::"), 0);
-                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
-                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
-                if (uid != INVALID_UID) {
-                    return uid;
-                }
-                wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
-                uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
-                        (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
-                if (uid != INVALID_UID) {
-                    return uid;
-                }
-            } catch (UnknownHostException e) {
-                Log.e(TAG, e.toString());
-            }
-        }
-        return INVALID_UID;
-    }
-
-    /**
-     * Use an inet_diag socket to look up the UID associated with the input local and remote
-     * address/port and protocol of a connection.
-     */
-    public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
-                                            InetSocketAddress remote) {
-        int uid = INVALID_UID;
-        FileDescriptor fd = null;
-        try {
-            fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
-            NetlinkSocket.connectToKernel(fd);
-            uid = lookupUid(protocol, local, remote, fd);
-        } catch (ErrnoException | SocketException | IllegalArgumentException
-                | InterruptedIOException e) {
-            Log.e(TAG, e.toString());
-        } finally {
-            if (fd != null) {
-                try {
-                    SocketUtils.closeSocket(fd);
-                } catch (IOException e) {
-                    Log.e(TAG, e.toString());
-                }
-            }
-        }
-        return uid;
-    }
-
-    @Override
-    public String toString() {
-        return "InetDiagMessage{ "
-                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
-                + "inet_diag_msg{"
-                + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
deleted file mode 100644
index fc1551c..0000000
--- a/services/net/java/android/net/netlink/NetlinkConstants.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.system.OsConstants;
-import com.android.internal.util.HexDump;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * Various constants and static helper methods for netlink communications.
- *
- * Values taken from:
- *
- *     &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *     &lt;linux_src&gt;/include/uapi/linux/rtnetlink.h
- *
- * @hide
- */
-public class NetlinkConstants {
-    private NetlinkConstants() {}
-
-    public static final int NLA_ALIGNTO = 4;
-
-    public static final int alignedLengthOf(short length) {
-        final int intLength = (int) length & 0xffff;
-        return alignedLengthOf(intLength);
-    }
-
-    public static final int alignedLengthOf(int length) {
-        if (length <= 0) { return 0; }
-        return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO);
-    }
-
-    public static String stringForAddressFamily(int family) {
-        if (family == OsConstants.AF_INET) { return "AF_INET"; }
-        if (family == OsConstants.AF_INET6) { return "AF_INET6"; }
-        if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; }
-        return String.valueOf(family);
-    }
-
-    public static String stringForProtocol(int protocol) {
-        if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
-        if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
-        return String.valueOf(protocol);
-    }
-
-    public static String hexify(byte[] bytes) {
-        if (bytes == null) { return "(null)"; }
-        return HexDump.toHexString(bytes);
-    }
-
-    public static String hexify(ByteBuffer buffer) {
-        if (buffer == null) { return "(null)"; }
-        return HexDump.toHexString(
-                buffer.array(), buffer.position(), buffer.remaining());
-    }
-
-    // Known values for struct nlmsghdr nlm_type.
-    public static final short NLMSG_NOOP         = 1;   // Nothing
-    public static final short NLMSG_ERROR        = 2;   // Error
-    public static final short NLMSG_DONE         = 3;   // End of a dump
-    public static final short NLMSG_OVERRUN      = 4;   // Data lost
-    public static final short NLMSG_MAX_RESERVED = 15;  // Max reserved value
-
-    public static final short RTM_NEWLINK        = 16;
-    public static final short RTM_DELLINK        = 17;
-    public static final short RTM_GETLINK        = 18;
-    public static final short RTM_SETLINK        = 19;
-    public static final short RTM_NEWADDR        = 20;
-    public static final short RTM_DELADDR        = 21;
-    public static final short RTM_GETADDR        = 22;
-    public static final short RTM_NEWROUTE       = 24;
-    public static final short RTM_DELROUTE       = 25;
-    public static final short RTM_GETROUTE       = 26;
-    public static final short RTM_NEWNEIGH       = 28;
-    public static final short RTM_DELNEIGH       = 29;
-    public static final short RTM_GETNEIGH       = 30;
-    public static final short RTM_NEWRULE        = 32;
-    public static final short RTM_DELRULE        = 33;
-    public static final short RTM_GETRULE        = 34;
-    public static final short RTM_NEWNDUSEROPT   = 68;
-
-    /* see &lt;linux_src&gt;/include/uapi/linux/sock_diag.h */
-    public static final short SOCK_DIAG_BY_FAMILY = 20;
-
-    public static String stringForNlMsgType(short nlm_type) {
-        switch (nlm_type) {
-            case NLMSG_NOOP: return "NLMSG_NOOP";
-            case NLMSG_ERROR: return "NLMSG_ERROR";
-            case NLMSG_DONE: return "NLMSG_DONE";
-            case NLMSG_OVERRUN: return "NLMSG_OVERRUN";
-            case RTM_NEWLINK: return "RTM_NEWLINK";
-            case RTM_DELLINK: return "RTM_DELLINK";
-            case RTM_GETLINK: return "RTM_GETLINK";
-            case RTM_SETLINK: return "RTM_SETLINK";
-            case RTM_NEWADDR: return "RTM_NEWADDR";
-            case RTM_DELADDR: return "RTM_DELADDR";
-            case RTM_GETADDR: return "RTM_GETADDR";
-            case RTM_NEWROUTE: return "RTM_NEWROUTE";
-            case RTM_DELROUTE: return "RTM_DELROUTE";
-            case RTM_GETROUTE: return "RTM_GETROUTE";
-            case RTM_NEWNEIGH: return "RTM_NEWNEIGH";
-            case RTM_DELNEIGH: return "RTM_DELNEIGH";
-            case RTM_GETNEIGH: return "RTM_GETNEIGH";
-            case RTM_NEWRULE: return "RTM_NEWRULE";
-            case RTM_DELRULE: return "RTM_DELRULE";
-            case RTM_GETRULE: return "RTM_GETRULE";
-            case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT";
-            default:
-                return "unknown RTM type: " + String.valueOf(nlm_type);
-        }
-    }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java
deleted file mode 100644
index e275574..0000000
--- a/services/net/java/android/net/netlink/NetlinkErrorMessage.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.StructNlMsgHdr;
-import android.net.netlink.NetlinkMessage;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * A NetlinkMessage subclass for netlink error messages.
- *
- * @hide
- */
-public class NetlinkErrorMessage extends NetlinkMessage {
-
-    public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header);
-
-        errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer);
-        if (errorMsg.mNlMsgErr == null) {
-            return null;
-        }
-
-        return errorMsg;
-    }
-
-    private StructNlMsgErr mNlMsgErr;
-
-    NetlinkErrorMessage(StructNlMsgHdr header) {
-        super(header);
-        mNlMsgErr = null;
-    }
-
-    public StructNlMsgErr getNlMsgError() {
-        return mNlMsgErr;
-    }
-
-    @Override
-    public String toString() {
-        return "NetlinkErrorMessage{ "
-                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
-                + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
deleted file mode 100644
index a325db8..0000000
--- a/services/net/java/android/net/netlink/NetlinkMessage.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNlAttr;
-import android.net.netlink.StructNlMsgHdr;
-import android.util.Log;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * NetlinkMessage base class for other, more specific netlink message types.
- *
- * Classes that extend NetlinkMessage should:
- *     - implement a public static parse(StructNlMsgHdr, ByteBuffer) method
- *     - returning either null (parse errors) or a new object of the subclass
- *       type (cast-able to NetlinkMessage)
- *
- * NetlinkMessage.parse() should be updated to know which nlmsg_type values
- * correspond with which message subclasses.
- *
- * @hide
- */
-public class NetlinkMessage {
-    private final static String TAG = "NetlinkMessage";
-
-    public static NetlinkMessage parse(ByteBuffer byteBuffer) {
-        final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1;
-        final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer);
-        if (nlmsghdr == null) {
-            return null;
-        }
-
-        int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len);
-        payloadLength -= StructNlMsgHdr.STRUCT_SIZE;
-        if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) {
-            // Malformed message or runt buffer.  Pretend the buffer was consumed.
-            byteBuffer.position(byteBuffer.limit());
-            return null;
-        }
-
-        switch (nlmsghdr.nlmsg_type) {
-            //case NetlinkConstants.NLMSG_NOOP:
-            case NetlinkConstants.NLMSG_ERROR:
-                return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
-            case NetlinkConstants.NLMSG_DONE:
-                byteBuffer.position(byteBuffer.position() + payloadLength);
-                return new NetlinkMessage(nlmsghdr);
-            //case NetlinkConstants.NLMSG_OVERRUN:
-            case NetlinkConstants.RTM_NEWNEIGH:
-            case NetlinkConstants.RTM_DELNEIGH:
-            case NetlinkConstants.RTM_GETNEIGH:
-                return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
-            case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
-                return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
-            default:
-                if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
-                    // Netlink control message.  Just parse the header for now,
-                    // pretending the whole message was consumed.
-                    byteBuffer.position(byteBuffer.position() + payloadLength);
-                    return new NetlinkMessage(nlmsghdr);
-                }
-                return null;
-        }
-    }
-
-    protected StructNlMsgHdr mHeader;
-
-    public NetlinkMessage(StructNlMsgHdr nlmsghdr) {
-        mHeader = nlmsghdr;
-    }
-
-    public StructNlMsgHdr getHeader() {
-        return mHeader;
-    }
-
-    @Override
-    public String toString() {
-        return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
deleted file mode 100644
index 7311fc5..0000000
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
-import static android.system.OsConstants.AF_NETLINK;
-import static android.system.OsConstants.EIO;
-import static android.system.OsConstants.EPROTO;
-import static android.system.OsConstants.ETIMEDOUT;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_RCVBUF;
-import static android.system.OsConstants.SO_RCVTIMEO;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-import android.net.util.SocketUtils;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * NetlinkSocket
- *
- * A small static class to assist with AF_NETLINK socket operations.
- *
- * @hide
- */
-public class NetlinkSocket {
-    private static final String TAG = "NetlinkSocket";
-
-    public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
-    public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
-
-    public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
-        final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
-        final long IO_TIMEOUT = 300L;
-
-        final FileDescriptor fd = forProto(nlProto);
-
-        try {
-            connectToKernel(fd);
-            sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
-            final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
-            // recvMessage() guaranteed to not return null if it did not throw.
-            final NetlinkMessage response = NetlinkMessage.parse(bytes);
-            if (response != null && response instanceof NetlinkErrorMessage &&
-                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
-                final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
-                if (errno != 0) {
-                    // TODO: consider ignoring EINVAL (-22), which appears to be
-                    // normal when probing a neighbor for which the kernel does
-                    // not already have / no longer has a link layer address.
-                    Log.e(TAG, errPrefix + ", errmsg=" + response.toString());
-                    // Note: convert kernel errnos (negative) into userspace errnos (positive).
-                    throw new ErrnoException(response.toString(), Math.abs(errno));
-                }
-            } else {
-                final String errmsg;
-                if (response == null) {
-                    bytes.position(0);
-                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
-                } else {
-                    errmsg = response.toString();
-                }
-                Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
-                throw new ErrnoException(errmsg, EPROTO);
-            }
-        } catch (InterruptedIOException e) {
-            Log.e(TAG, errPrefix, e);
-            throw new ErrnoException(errPrefix, ETIMEDOUT, e);
-        } catch (SocketException e) {
-            Log.e(TAG, errPrefix, e);
-            throw new ErrnoException(errPrefix, EIO, e);
-        } finally {
-            try {
-                SocketUtils.closeSocket(fd);
-            } catch (IOException e) {
-                // Nothing we can do here
-            }
-        }
-    }
-
-    public static FileDescriptor forProto(int nlProto) throws ErrnoException {
-        final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
-        Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
-        return fd;
-    }
-
-    public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
-        Os.connect(fd, makeNetlinkSocketAddress(0, 0));
-    }
-
-    private static void checkTimeout(long timeoutMs) {
-        if (timeoutMs < 0) {
-            throw new IllegalArgumentException("Negative timeouts not permitted");
-        }
-    }
-
-    /**
-     * Wait up to |timeoutMs| (or until underlying socket error) for a
-     * netlink message of at most |bufsize| size.
-     *
-     * Multi-threaded calls with different timeouts will cause unexpected results.
-     */
-    public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
-            throws ErrnoException, IllegalArgumentException, InterruptedIOException {
-        checkTimeout(timeoutMs);
-
-        Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
-
-        ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
-        int length = Os.read(fd, byteBuffer);
-        if (length == bufsize) {
-            Log.w(TAG, "maximum read");
-        }
-        byteBuffer.position(0);
-        byteBuffer.limit(length);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        return byteBuffer;
-    }
-
-    /**
-     * Send a message to a peer to which this socket has previously connected,
-     * waiting at most |timeoutMs| milliseconds for the send to complete.
-     *
-     * Multi-threaded calls with different timeouts will cause unexpected results.
-     */
-    public static int sendMessage(
-            FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
-            throws ErrnoException, IllegalArgumentException, InterruptedIOException {
-        checkTimeout(timeoutMs);
-        Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
-        return Os.write(fd, bytes, offset, count);
-    }
-}
diff --git a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
deleted file mode 100644
index e784fbb..0000000
--- a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import android.net.netlink.StructNdaCacheInfo;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlAttr;
-import android.net.netlink.StructNlMsgHdr;
-import android.net.netlink.NetlinkMessage;
-import android.system.OsConstants;
-import android.util.Log;
-
-import java.net.InetAddress;
-import java.net.Inet6Address;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-
-/**
- * A NetlinkMessage subclass for rtnetlink neighbor messages.
- *
- * see also: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class RtNetlinkNeighborMessage extends NetlinkMessage {
-    public static final short NDA_UNSPEC    = 0;
-    public static final short NDA_DST       = 1;
-    public static final short NDA_LLADDR    = 2;
-    public static final short NDA_CACHEINFO = 3;
-    public static final short NDA_PROBES    = 4;
-    public static final short NDA_VLAN      = 5;
-    public static final short NDA_PORT      = 6;
-    public static final short NDA_VNI       = 7;
-    public static final short NDA_IFINDEX   = 8;
-    public static final short NDA_MASTER    = 9;
-
-    private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) {
-        while (byteBuffer != null && byteBuffer.remaining() > 0) {
-            final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer);
-            if (nlAttr == null) {
-                break;
-            }
-            if (nlAttr.nla_type == attrType) {
-                return StructNlAttr.parse(byteBuffer);
-            }
-            if (byteBuffer.remaining() < nlAttr.getAlignedLength()) {
-                break;
-            }
-            byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength());
-        }
-        return null;
-    }
-
-    public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
-        final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header);
-
-        neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer);
-        if (neighMsg.mNdmsg == null) {
-            return null;
-        }
-
-        // Some of these are message-type dependent, and not always present.
-        final int baseOffset = byteBuffer.position();
-        StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mDestination = nlAttr.getValueAsInetAddress();
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mLinkLayerAddr = nlAttr.nla_value;
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mNumProbes = nlAttr.getValueAsInt(0);
-        }
-
-        byteBuffer.position(baseOffset);
-        nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer);
-        if (nlAttr != null) {
-            neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer());
-        }
-
-        final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        final int kAdditionalSpace = NetlinkConstants.alignedLengthOf(
-                neighMsg.mHeader.nlmsg_len - kMinConsumed);
-        if (byteBuffer.remaining() < kAdditionalSpace) {
-            byteBuffer.position(byteBuffer.limit());
-        } else {
-            byteBuffer.position(baseOffset + kAdditionalSpace);
-        }
-
-        return neighMsg;
-    }
-
-    /**
-     * A convenience method to create an RTM_GETNEIGH request message.
-     */
-    public static byte[] newGetNeighborsRequest(int seqNo) {
-        final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        final byte[] bytes = new byte[length];
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
-        nlmsghdr.nlmsg_len = length;
-        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
-        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-        nlmsghdr.nlmsg_seq = seqNo;
-        nlmsghdr.pack(byteBuffer);
-
-        final StructNdMsg ndmsg = new StructNdMsg();
-        ndmsg.pack(byteBuffer);
-
-        return bytes;
-    }
-
-    /**
-     * A convenience method to create an RTM_NEWNEIGH message, to modify
-     * the kernel's state information for a specific neighbor.
-     */
-    public static byte[] newNewNeighborMessage(
-            int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
-        final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
-        nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
-        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
-        nlmsghdr.nlmsg_seq = seqNo;
-
-        final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
-        msg.mNdmsg = new StructNdMsg();
-        msg.mNdmsg.ndm_family =
-                (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
-        msg.mNdmsg.ndm_ifindex = ifIndex;
-        msg.mNdmsg.ndm_state = nudState;
-        msg.mDestination = ip;
-        msg.mLinkLayerAddr = llAddr;  // might be null
-
-        final byte[] bytes = new byte[msg.getRequiredSpace()];
-        nlmsghdr.nlmsg_len = bytes.length;
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
-        byteBuffer.order(ByteOrder.nativeOrder());
-        msg.pack(byteBuffer);
-        return bytes;
-    }
-
-    private StructNdMsg mNdmsg;
-    private InetAddress mDestination;
-    private byte[] mLinkLayerAddr;
-    private int mNumProbes;
-    private StructNdaCacheInfo mCacheInfo;
-
-    private RtNetlinkNeighborMessage(StructNlMsgHdr header) {
-        super(header);
-        mNdmsg = null;
-        mDestination = null;
-        mLinkLayerAddr = null;
-        mNumProbes = 0;
-        mCacheInfo = null;
-    }
-
-    public StructNdMsg getNdHeader() {
-        return mNdmsg;
-    }
-
-    public InetAddress getDestination() {
-        return mDestination;
-    }
-
-    public byte[] getLinkLayerAddress() {
-        return mLinkLayerAddr;
-    }
-
-    public int getProbes() {
-        return mNumProbes;
-    }
-
-    public StructNdaCacheInfo getCacheInfo() {
-        return mCacheInfo;
-    }
-
-    public int getRequiredSpace() {
-        int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE;
-        if (mDestination != null) {
-            spaceRequired += NetlinkConstants.alignedLengthOf(
-                    StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length);
-        }
-        if (mLinkLayerAddr != null) {
-            spaceRequired += NetlinkConstants.alignedLengthOf(
-                    StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length);
-        }
-        // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO
-        // attributes appended.  Fix later, if necessary.
-        return spaceRequired;
-    }
-
-    private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) {
-        final StructNlAttr nlAttr = new StructNlAttr();
-        nlAttr.nla_type = nlType;
-        nlAttr.nla_value = nlValue;
-        nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length);
-        nlAttr.pack(byteBuffer);
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        getHeader().pack(byteBuffer) ;
-        mNdmsg.pack(byteBuffer);
-
-        if (mDestination != null) {
-            packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer);
-        }
-        if (mLinkLayerAddr != null) {
-            packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress();
-        return "RtNetlinkNeighborMessage{ "
-                + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
-                + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, "
-                + "destination{" + ipLiteral + "} "
-                + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} "
-                + "probes{" + mNumProbes + "} "
-                + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java
deleted file mode 100644
index da824ad..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagMsg.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.netlink;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import android.util.Log;
-
-/**
- * struct inet_diag_msg
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_msg {
- *      __u8    idiag_family;
- *      __u8    idiag_state;
- *      __u8    idiag_timer;
- *      __u8    idiag_retrans;
- *      struct  inet_diag_sockid id;
- *      __u32   idiag_expires;
- *      __u32   idiag_rqueue;
- *      __u32   idiag_wqueue;
- *      __u32   idiag_uid;
- *      __u32   idiag_inode;
- * };
- *
- * @hide
- */
-public class StructInetDiagMsg {
-    public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
-    private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
-            StructInetDiagSockId.STRUCT_SIZE + 12;
-    public int idiag_uid;
-
-    public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
-        StructInetDiagMsg struct = new StructInetDiagMsg();
-        struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
-        return struct;
-    }
-
-    @Override
-    public String toString() {
-        return "StructInetDiagMsg{ "
-                + "idiag_uid{" + idiag_uid + "}, "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
deleted file mode 100644
index 2268113..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagReqV2.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.netlink;
-
-import android.annotation.Nullable;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-
-/**
- * struct inet_diag_req_v2
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- *      struct inet_diag_req_v2 {
- *          __u8    sdiag_family;
- *          __u8    sdiag_protocol;
- *          __u8    idiag_ext;
- *          __u8    pad;
- *          __u32   idiag_states;
- *          struct  inet_diag_sockid id;
- *      };
- *
- * @hide
- */
-public class StructInetDiagReqV2 {
-    public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
-
-    private final byte mSdiagFamily;
-    private final byte mSdiagProtocol;
-    private final byte mIdiagExt;
-    private final byte mPad;
-    private final StructInetDiagSockId mId;
-    private final int mState;
-    public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
-
-    public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
-            int family) {
-        this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
-                INET_DIAG_REQ_V2_ALL_STATES);
-    }
-
-    public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
-            @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
-            throws NullPointerException {
-        mSdiagFamily = (byte) family;
-        mSdiagProtocol = (byte) protocol;
-        // Request for all sockets if no specific socket is requested. Specify the local and remote
-        // socket address information for target request socket.
-        if ((local == null) != (remote == null)) {
-            throw new NullPointerException("Local and remote must be both null or both non-null");
-        }
-        mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
-        mPad = (byte) pad;
-        mIdiagExt = (byte) extension;
-        mState = state;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.
-        byteBuffer.put((byte) mSdiagFamily);
-        byteBuffer.put((byte) mSdiagProtocol);
-        byteBuffer.put((byte) mIdiagExt);
-        byteBuffer.put((byte) mPad);
-        byteBuffer.putInt(mState);
-        if (mId != null) mId.pack(byteBuffer);
-    }
-
-    @Override
-    public String toString() {
-        final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
-        final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
-
-        return "StructInetDiagReqV2{ "
-                + "sdiag_family{" + familyStr + "}, "
-                + "sdiag_protocol{" + protocolStr + "}, "
-                + "idiag_ext{" + mIdiagExt + ")}, "
-                + "pad{" + mPad + "}, "
-                + "idiag_states{" + Integer.toHexString(mState) + "}, "
-                + ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java
deleted file mode 100644
index 2e9fa25..0000000
--- a/services/net/java/android/net/netlink/StructInetDiagSockId.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.netlink;
-
-import static java.nio.ByteOrder.BIG_ENDIAN;
-
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * struct inet_diag_req_v2
- *
- * see &lt;linux_src&gt;/include/uapi/linux/inet_diag.h
- *
- * struct inet_diag_sockid {
- *        __be16    idiag_sport;
- *        __be16    idiag_dport;
- *        __be32    idiag_src[4];
- *        __be32    idiag_dst[4];
- *        __u32     idiag_if;
- *        __u32     idiag_cookie[2];
- * #define INET_DIAG_NOCOOKIE (~0U)
- * };
- *
- * @hide
- */
-public class StructInetDiagSockId {
-    public static final int STRUCT_SIZE = 48;
-
-    private final InetSocketAddress mLocSocketAddress;
-    private final InetSocketAddress mRemSocketAddress;
-    private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
-    private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-    public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
-        mLocSocketAddress = loc;
-        mRemSocketAddress = rem;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        byteBuffer.order(BIG_ENDIAN);
-        byteBuffer.putShort((short) mLocSocketAddress.getPort());
-        byteBuffer.putShort((short) mRemSocketAddress.getPort());
-        byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
-        if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
-            byteBuffer.put(IPV4_PADDING);
-        }
-        byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
-        if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
-            byteBuffer.put(IPV4_PADDING);
-        }
-        byteBuffer.order(ByteOrder.nativeOrder());
-        byteBuffer.putInt(0);
-        byteBuffer.put(INET_DIAG_NOCOOKIE);
-    }
-
-    @Override
-    public String toString() {
-        return "StructInetDiagSockId{ "
-                + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
-                + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
-                + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
-                + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
-                + "idiag_if{" + 0 + "} "
-                + "idiag_cookie{INET_DIAG_NOCOOKIE}"
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
deleted file mode 100644
index e34ec39..0000000
--- a/services/net/java/android/net/netlink/StructNdMsg.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.system.OsConstants;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct ndmsg
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdMsg {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 12;
-
-    // Neighbor Cache Entry States
-    public static final short NUD_NONE        = 0x00;
-    public static final short NUD_INCOMPLETE  = 0x01;
-    public static final short NUD_REACHABLE   = 0x02;
-    public static final short NUD_STALE       = 0x04;
-    public static final short NUD_DELAY       = 0x08;
-    public static final short NUD_PROBE       = 0x10;
-    public static final short NUD_FAILED      = 0x20;
-    public static final short NUD_NOARP       = 0x40;
-    public static final short NUD_PERMANENT   = 0x80;
-
-    public static String stringForNudState(short nudState) {
-        switch (nudState) {
-            case NUD_NONE: return "NUD_NONE";
-            case NUD_INCOMPLETE: return "NUD_INCOMPLETE";
-            case NUD_REACHABLE: return "NUD_REACHABLE";
-            case NUD_STALE: return "NUD_STALE";
-            case NUD_DELAY: return "NUD_DELAY";
-            case NUD_PROBE: return "NUD_PROBE";
-            case NUD_FAILED: return "NUD_FAILED";
-            case NUD_NOARP: return "NUD_NOARP";
-            case NUD_PERMANENT: return "NUD_PERMANENT";
-            default:
-                return "unknown NUD state: " + String.valueOf(nudState);
-        }
-    }
-
-    public static boolean isNudStateConnected(short nudState) {
-        return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
-    }
-
-    public static boolean isNudStateValid(short nudState) {
-        return (isNudStateConnected(nudState) ||
-                ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
-    }
-
-    // Neighbor Cache Entry Flags
-    public static byte NTF_USE       = (byte) 0x01;
-    public static byte NTF_SELF      = (byte) 0x02;
-    public static byte NTF_MASTER    = (byte) 0x04;
-    public static byte NTF_PROXY     = (byte) 0x08;
-    public static byte NTF_ROUTER    = (byte) 0x80;
-
-    public static String stringForNudFlags(byte flags) {
-        final StringBuilder sb = new StringBuilder();
-        if ((flags & NTF_USE) != 0) {
-            sb.append("NTF_USE");
-        }
-        if ((flags & NTF_SELF) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_SELF");
-        }
-        if ((flags & NTF_MASTER) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_MASTER");
-        }
-        if ((flags & NTF_PROXY) != 0) {
-            if (sb.length() > 0) { sb.append("|");
-        }
-            sb.append("NTF_PROXY"); }
-        if ((flags & NTF_ROUTER) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NTF_ROUTER");
-        }
-        return sb.toString();
-    }
-
-    private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNdMsg parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        final StructNdMsg struct = new StructNdMsg();
-        struct.ndm_family = byteBuffer.get();
-        final byte pad1 = byteBuffer.get();
-        final short pad2 = byteBuffer.getShort();
-        struct.ndm_ifindex = byteBuffer.getInt();
-        struct.ndm_state = byteBuffer.getShort();
-        struct.ndm_flags = byteBuffer.get();
-        struct.ndm_type = byteBuffer.get();
-        return struct;
-    }
-
-    public byte ndm_family;
-    public int ndm_ifindex;
-    public short ndm_state;
-    public byte ndm_flags;
-    public byte ndm_type;
-
-    public StructNdMsg() {
-        ndm_family = (byte) OsConstants.AF_UNSPEC;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        byteBuffer.put(ndm_family);
-        byteBuffer.put((byte) 0);         // pad1
-        byteBuffer.putShort((short) 0);   // pad2
-        byteBuffer.putInt(ndm_ifindex);
-        byteBuffer.putShort(ndm_state);
-        byteBuffer.put(ndm_flags);
-        byteBuffer.put(ndm_type);
-    }
-
-    public boolean nudConnected() {
-        return isNudStateConnected(ndm_state);
-    }
-
-    public boolean nudValid() {
-        return isNudStateValid(ndm_state);
-    }
-
-    @Override
-    public String toString() {
-        final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")";
-        final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")";
-        return "StructNdMsg{ "
-                + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, "
-                + "ifindex{" + ndm_ifindex + "}, "
-                + "state{" + stateStr + "}, "
-                + "flags{" + flagsStr + "}, "
-                + "type{" + ndm_type + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java
deleted file mode 100644
index 16cf563..0000000
--- a/services/net/java/android/net/netlink/StructNdaCacheInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.system.Os;
-import android.system.OsConstants;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nda_cacheinfo
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/neighbour.h
- *
- * @hide
- */
-public class StructNdaCacheInfo {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 16;
-
-    private static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        final StructNdaCacheInfo struct = new StructNdaCacheInfo();
-        struct.ndm_used = byteBuffer.getInt();
-        struct.ndm_confirmed = byteBuffer.getInt();
-        struct.ndm_updated = byteBuffer.getInt();
-        struct.ndm_refcnt = byteBuffer.getInt();
-        return struct;
-    }
-
-    // TODO: investigate whether this can change during device runtime and
-    // decide what (if anything) should be done about that.
-    private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK);
-
-    private static long ticksToMilliSeconds(int intClockTicks) {
-        final long longClockTicks = (long) intClockTicks & 0xffffffff;
-        return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND;
-    }
-
-    /**
-     * Explanatory notes, for reference.
-     *
-     * Before being returned to user space, the neighbor entry times are
-     * converted to clock_t's like so:
-     *
-     *     ndm_used      = jiffies_to_clock_t(now - neigh->used);
-     *     ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
-     *     ndm_updated   = jiffies_to_clock_t(now - neigh->updated);
-     *
-     * meaning that these values are expressed as "clock ticks ago".  To
-     * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
-     * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
-     * in centiseconds.
-     *
-     * These values are unsigned, but fortunately being expressed as "some
-     * clock ticks ago", these values are typically very small (and 
-     * 2^31 centiseconds = 248 days).
-     *
-     * By observation, it appears that:
-     *     ndm_used: the last time ARP/ND took place for this neighbor
-     *     ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR
-     *                    higher layer confirmation (TCP or MSG_CONFIRM)
-     *                    was received
-     *     ndm_updated: the time when the current NUD state was entered
-     */
-    public int ndm_used;
-    public int ndm_confirmed;
-    public int ndm_updated;
-    public int ndm_refcnt;
-
-    public StructNdaCacheInfo() {}
-
-    public long lastUsed() {
-        return ticksToMilliSeconds(ndm_used);
-    }
-
-    public long lastConfirmed() {
-        return ticksToMilliSeconds(ndm_confirmed);
-    }
-
-    public long lastUpdated() {
-        return ticksToMilliSeconds(ndm_updated);
-    }
-
-    @Override
-    public String toString() {
-        return "NdaCacheInfo{ "
-                + "ndm_used{" + lastUsed() + "}, "
-                + "ndm_confirmed{" + lastConfirmed() + "}, "
-                + "ndm_updated{" + lastUpdated() + "}, "
-                + "ndm_refcnt{" + ndm_refcnt + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNfGenMsg.java b/services/net/java/android/net/netlink/StructNfGenMsg.java
deleted file mode 100644
index 8155977..0000000
--- a/services/net/java/android/net/netlink/StructNfGenMsg.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nfgenmsg
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netfilter/nfnetlink.h
- *
- * @hide
- */
-public class StructNfGenMsg {
-    public static final int STRUCT_SIZE = 2 + Short.BYTES;
-
-    public static final int NFNETLINK_V0 = 0;
-
-    final public byte nfgen_family;
-    final public byte version;
-    final public short res_id;  // N.B.: this is big endian in the kernel
-
-    public StructNfGenMsg(byte family) {
-        nfgen_family = family;
-        version = (byte) NFNETLINK_V0;
-        res_id = (short) 0;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        byteBuffer.put(nfgen_family);
-        byteBuffer.put(version);
-        byteBuffer.putShort(res_id);
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java
deleted file mode 100644
index 28a4e88..0000000
--- a/services/net/java/android/net/netlink/StructNlAttr.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteOrder;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlattr
- *
- * see: &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlAttr {
-    // Already aligned.
-    public static final int NLA_HEADERLEN  = 4;
-    public static final int NLA_F_NESTED   = (1 << 15);
-
-    public static short makeNestedType(short type) {
-        return (short) (type | NLA_F_NESTED);
-    }
-
-    // Return a (length, type) object only, without consuming any bytes in
-    // |byteBuffer| and without copying or interpreting any value bytes.
-    // This is used for scanning over a packed set of struct nlattr's,
-    // looking for instances of a particular type.
-    public static StructNlAttr peek(ByteBuffer byteBuffer) {
-        if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) {
-            return null;
-        }
-        final int baseOffset = byteBuffer.position();
-
-        // Assume the byte order of the buffer is the expected byte order of the value.
-        final StructNlAttr struct = new StructNlAttr(byteBuffer.order());
-        // The byte order of nla_len and nla_type is always native.
-        final ByteOrder originalOrder = byteBuffer.order();
-        byteBuffer.order(ByteOrder.nativeOrder());
-        try {
-            struct.nla_len = byteBuffer.getShort();
-            struct.nla_type = byteBuffer.getShort();
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-
-        byteBuffer.position(baseOffset);
-        if (struct.nla_len < NLA_HEADERLEN) {
-            // Malformed.
-            return null;
-        }
-        return struct;
-    }
-
-    public static StructNlAttr parse(ByteBuffer byteBuffer) {
-        final StructNlAttr struct = peek(byteBuffer);
-        if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) {
-            return null;
-        }
-
-        final int baseOffset = byteBuffer.position();
-        byteBuffer.position(baseOffset + NLA_HEADERLEN);
-
-        int valueLen = ((int) struct.nla_len) & 0xffff;
-        valueLen -= NLA_HEADERLEN;
-        if (valueLen > 0) {
-            struct.nla_value = new byte[valueLen];
-            byteBuffer.get(struct.nla_value, 0, valueLen);
-            byteBuffer.position(baseOffset + struct.getAlignedLength());
-        }
-        return struct;
-    }
-
-    public short nla_len = (short) NLA_HEADERLEN;
-    public short nla_type;
-    public byte[] nla_value;
-
-    // The byte order used to read/write the value member. Netlink length and
-    // type members are always read/written in native order.
-    private ByteOrder mByteOrder = ByteOrder.nativeOrder();
-
-    public StructNlAttr() {}
-
-    public StructNlAttr(ByteOrder byteOrder) {
-        mByteOrder = byteOrder;
-    }
-
-    public StructNlAttr(short type, byte value) {
-        nla_type = type;
-        setValue(new byte[1]);
-        nla_value[0] = value;
-    }
-
-    public StructNlAttr(short type, short value) {
-        this(type, value, ByteOrder.nativeOrder());
-    }
-
-    public StructNlAttr(short type, short value, ByteOrder order) {
-        this(order);
-        nla_type = type;
-        setValue(new byte[Short.BYTES]);
-        getValueAsByteBuffer().putShort(value);
-    }
-
-    public StructNlAttr(short type, int value) {
-        this(type, value, ByteOrder.nativeOrder());
-    }
-
-    public StructNlAttr(short type, int value, ByteOrder order) {
-        this(order);
-        nla_type = type;
-        setValue(new byte[Integer.BYTES]);
-        getValueAsByteBuffer().putInt(value);
-    }
-
-    public StructNlAttr(short type, InetAddress ip) {
-        nla_type = type;
-        setValue(ip.getAddress());
-    }
-
-    public StructNlAttr(short type, StructNlAttr... nested) {
-        this();
-        nla_type = makeNestedType(type);
-
-        int payloadLength = 0;
-        for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength();
-        setValue(new byte[payloadLength]);
-
-        final ByteBuffer buf = getValueAsByteBuffer();
-        for (StructNlAttr nla : nested) {
-            nla.pack(buf);
-        }
-    }
-
-    public int getAlignedLength() {
-        return NetlinkConstants.alignedLengthOf(nla_len);
-    }
-
-    public ByteBuffer getValueAsByteBuffer() {
-        if (nla_value == null) { return null; }
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value);
-        byteBuffer.order(mByteOrder);
-        return byteBuffer;
-    }
-
-    public int getValueAsInt(int defaultValue) {
-        final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
-            return defaultValue;
-        }
-        return getValueAsByteBuffer().getInt();
-    }
-
-    public InetAddress getValueAsInetAddress() {
-        if (nla_value == null) { return null; }
-
-        try {
-            return InetAddress.getByAddress(nla_value);
-        } catch (UnknownHostException ignored) {
-            return null;
-        }
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        final ByteOrder originalOrder = byteBuffer.order();
-        final int originalPosition = byteBuffer.position();
-
-        byteBuffer.order(ByteOrder.nativeOrder());
-        try {
-            byteBuffer.putShort(nla_len);
-            byteBuffer.putShort(nla_type);
-            if (nla_value != null) byteBuffer.put(nla_value);
-        } finally {
-            byteBuffer.order(originalOrder);
-        }
-        byteBuffer.position(originalPosition + getAlignedLength());
-    }
-
-    private void setValue(byte[] value) {
-        nla_value = value;
-        nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0));
-    }
-
-    @Override
-    public String toString() {
-        return "StructNlAttr{ "
-                + "nla_len{" + nla_len + "}, "
-                + "nla_type{" + nla_type + "}, "
-                + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java
deleted file mode 100644
index 6fcc6e6..0000000
--- a/services/net/java/android/net/netlink/StructNlMsgErr.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.StructNlMsgHdr;
-
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsgerr
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgErr {
-    public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE;
-
-    public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNlMsgErr parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        final StructNlMsgErr struct = new StructNlMsgErr();
-        struct.error = byteBuffer.getInt();
-        struct.msg = StructNlMsgHdr.parse(byteBuffer);
-        return struct;
-    }
-
-    public int error;
-    public StructNlMsgHdr msg;
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        byteBuffer.putInt(error);
-        if (msg != null) {
-            msg.pack(byteBuffer);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "StructNlMsgErr{ "
-                + "error{" + error + "}, "
-                + "msg{" + (msg == null ? "" : msg.toString()) + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java
deleted file mode 100644
index 98ab5e7..0000000
--- a/services/net/java/android/net/netlink/StructNlMsgHdr.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import android.net.netlink.NetlinkConstants;
-import java.nio.ByteBuffer;
-
-
-/**
- * struct nlmsghdr
- *
- * see &lt;linux_src&gt;/include/uapi/linux/netlink.h
- *
- * @hide
- */
-public class StructNlMsgHdr {
-    // Already aligned.
-    public static final int STRUCT_SIZE = 16;
-
-    public static final short NLM_F_REQUEST = 0x0001;
-    public static final short NLM_F_MULTI   = 0x0002;
-    public static final short NLM_F_ACK     = 0x0004;
-    public static final short NLM_F_ECHO    = 0x0008;
-    // Flags for a GET request.
-    public static final short NLM_F_ROOT    = 0x0100;
-    public static final short NLM_F_MATCH   = 0x0200;
-    public static final short NLM_F_DUMP    = NLM_F_ROOT|NLM_F_MATCH;
-    // Flags for a NEW request.
-    public static final short NLM_F_REPLACE   = 0x100;
-    public static final short NLM_F_EXCL      = 0x200;
-    public static final short NLM_F_CREATE    = 0x400;
-    public static final short NLM_F_APPEND    = 0x800;
-
-
-    public static String stringForNlMsgFlags(short flags) {
-        final StringBuilder sb = new StringBuilder();
-        if ((flags & NLM_F_REQUEST) != 0) {
-            sb.append("NLM_F_REQUEST");
-        }
-        if ((flags & NLM_F_MULTI) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_MULTI");
-        }
-        if ((flags & NLM_F_ACK) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ACK");
-        }
-        if ((flags & NLM_F_ECHO) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ECHO");
-        }
-        if ((flags & NLM_F_ROOT) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_ROOT");
-        }
-        if ((flags & NLM_F_MATCH) != 0) {
-            if (sb.length() > 0) { sb.append("|"); }
-            sb.append("NLM_F_MATCH");
-        }
-        return sb.toString();
-    }
-
-    public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
-        return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
-    }
-
-    public static StructNlMsgHdr parse(ByteBuffer byteBuffer) {
-        if (!hasAvailableSpace(byteBuffer)) { return null; }
-
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the exception
-        // of usage within unittests.
-        final StructNlMsgHdr struct = new StructNlMsgHdr();
-        struct.nlmsg_len = byteBuffer.getInt();
-        struct.nlmsg_type = byteBuffer.getShort();
-        struct.nlmsg_flags = byteBuffer.getShort();
-        struct.nlmsg_seq = byteBuffer.getInt();
-        struct.nlmsg_pid = byteBuffer.getInt();
-
-        if (struct.nlmsg_len < STRUCT_SIZE) {
-            // Malformed.
-            return null;
-        }
-        return struct;
-    }
-
-    public int nlmsg_len;
-    public short nlmsg_type;
-    public short nlmsg_flags;
-    public int nlmsg_seq;
-    public int nlmsg_pid;
-
-    public StructNlMsgHdr() {
-        nlmsg_len = 0;
-        nlmsg_type = 0;
-        nlmsg_flags = 0;
-        nlmsg_seq = 0;
-        nlmsg_pid = 0;
-    }
-
-    public void pack(ByteBuffer byteBuffer) {
-        // The ByteOrder must have already been set by the caller.  In most
-        // cases ByteOrder.nativeOrder() is correct, with the possible
-        // exception of usage within unittests.
-        byteBuffer.putInt(nlmsg_len);
-        byteBuffer.putShort(nlmsg_type);
-        byteBuffer.putShort(nlmsg_flags);
-        byteBuffer.putInt(nlmsg_seq);
-        byteBuffer.putInt(nlmsg_pid);
-    }
-
-    @Override
-    public String toString() {
-        final String typeStr = "" + nlmsg_type
-                + "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")";
-        final String flagsStr = "" + nlmsg_flags
-                + "(" + stringForNlMsgFlags(nlmsg_flags) + ")";
-        return "StructNlMsgHdr{ "
-                + "nlmsg_len{" + nlmsg_len + "}, "
-                + "nlmsg_type{" + typeStr + "}, "
-                + "nlmsg_flags{" + flagsStr + ")}, "
-                + "nlmsg_seq{" + nlmsg_seq + "}, "
-                + "nlmsg_pid{" + nlmsg_pid + "} "
-                + "}";
-    }
-}
diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java
deleted file mode 100644
index 007c8ca9..0000000
--- a/services/net/java/android/net/shared/InitialConfiguration.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import static android.net.shared.ParcelableUtil.fromParcelableArray;
-import static android.net.shared.ParcelableUtil.toParcelableArray;
-import static android.text.TextUtils.join;
-
-import android.net.InetAddresses;
-import android.net.InitialConfigurationParcelable;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Predicate;
-
-/** @hide */
-public class InitialConfiguration {
-    public final Set<LinkAddress> ipAddresses = new HashSet<>();
-    public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
-    public final Set<InetAddress> dnsServers = new HashSet<>();
-
-    private static final int RFC6177_MIN_PREFIX_LENGTH = 48;
-    private static final int RFC7421_PREFIX_LENGTH = 64;
-
-    public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::");
-
-    /**
-     * Create a InitialConfiguration that is a copy of the specified configuration.
-     */
-    public static InitialConfiguration copy(InitialConfiguration config) {
-        if (config == null) {
-            return null;
-        }
-        InitialConfiguration configCopy = new InitialConfiguration();
-        configCopy.ipAddresses.addAll(config.ipAddresses);
-        configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
-        configCopy.dnsServers.addAll(config.dnsServers);
-        return configCopy;
-    }
-
-    @Override
-    public String toString() {
-        return String.format(
-                "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})",
-                join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
-                join(", ", dnsServers));
-    }
-
-    /**
-     * Tests whether the contents of this IpConfiguration represent a valid configuration.
-     */
-    public boolean isValid() {
-        if (ipAddresses.isEmpty()) {
-            return false;
-        }
-
-        // For every IP address, there must be at least one prefix containing that address.
-        for (LinkAddress addr : ipAddresses) {
-            if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
-                return false;
-            }
-        }
-        // For every dns server, there must be at least one prefix containing that address.
-        for (InetAddress addr : dnsServers) {
-            if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
-                return false;
-            }
-        }
-        // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
-        // (read: compliant with RFC4291#section2.5.4).
-        if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
-            return false;
-        }
-        // If directlyConnectedRoutes contains an IPv6 default route
-        // then ipAddresses MUST contain at least one non-ULA GUA.
-        if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
-                && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
-            return false;
-        }
-        // The prefix length of routes in directlyConnectedRoutes be within reasonable
-        // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
-        if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
-            return false;
-        }
-        // There no more than one IPv4 address
-        if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * @return true if the given list of addressess and routes satisfies provisioning for this
-     * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
-     * because addresses and routes seen by Netlink will contain additional fields like flags,
-     * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
-     * provisioning check always fails.
-     *
-     * If the given list of routes is null, only addresses are taken into considerations.
-     */
-    public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
-        if (ipAddresses.isEmpty()) {
-            return false;
-        }
-
-        for (LinkAddress addr : ipAddresses) {
-            if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
-                return false;
-            }
-        }
-
-        if (routes != null) {
-            for (IpPrefix prefix : directlyConnectedRoutes) {
-                if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Convert this configuration to a {@link InitialConfigurationParcelable}.
-     */
-    public InitialConfigurationParcelable toStableParcelable() {
-        final InitialConfigurationParcelable p = new InitialConfigurationParcelable();
-        p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]);
-        p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]);
-        p.dnsServers = toParcelableArray(
-                dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
-        return p;
-    }
-
-    /**
-     * Create an instance of {@link InitialConfiguration} based on the contents of the specified
-     * {@link InitialConfigurationParcelable}.
-     */
-    public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) {
-        if (p == null) return null;
-        final InitialConfiguration config = new InitialConfiguration();
-        config.ipAddresses.addAll(Arrays.asList(p.ipAddresses));
-        config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes));
-        config.dnsServers.addAll(
-                fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
-        return config;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof InitialConfiguration)) return false;
-        final InitialConfiguration other = (InitialConfiguration) obj;
-        return ipAddresses.equals(other.ipAddresses)
-                && directlyConnectedRoutes.equals(other.directlyConnectedRoutes)
-                && dnsServers.equals(other.dnsServers);
-    }
-
-    private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
-        return !route.hasGateway() && prefix.equals(route.getDestination());
-    }
-
-    private static boolean isPrefixLengthCompliant(LinkAddress addr) {
-        return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength());
-    }
-
-    private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
-        return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
-    }
-
-    private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
-        return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
-                && (prefixLength <= RFC7421_PREFIX_LENGTH);
-    }
-
-    private static boolean isIPv4(IpPrefix prefix) {
-        return prefix.getAddress() instanceof Inet4Address;
-    }
-
-    private static boolean isIPv4(LinkAddress addr) {
-        return addr.getAddress() instanceof Inet4Address;
-    }
-
-    private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
-        return prefix.getAddress().equals(INET6_ANY);
-    }
-
-    private static boolean isIPv6GUA(LinkAddress addr) {
-        return addr.isIpv6() && addr.isGlobalPreferred();
-    }
-
-    // TODO: extract out into CollectionUtils.
-
-    /**
-     * Indicate whether any element of the specified iterable verifies the specified predicate.
-     */
-    public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
-        for (T t : coll) {
-            if (fn.test(t)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Indicate whether all elements of the specified iterable verifies the specified predicate.
-     */
-    public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
-        return !any(coll, not(fn));
-    }
-
-    /**
-     * Create a predicate that returns the opposite value of the specified predicate.
-     */
-    public static <T> Predicate<T> not(Predicate<T> fn) {
-        return (t) -> !fn.test(t);
-    }
-}
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
deleted file mode 100644
index 172dc24..0000000
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.DhcpResultsParcelable;
-import android.net.InetAddresses;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-/**
- * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient
- * configuration classes.
- * @hide
- */
-public final class IpConfigurationParcelableUtil {
-    /**
-     * Convert DhcpResults to a DhcpResultsParcelable.
-     */
-    public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
-        if (results == null) return null;
-        final DhcpResultsParcelable p = new DhcpResultsParcelable();
-        p.baseConfiguration = results.toStaticIpConfiguration();
-        p.leaseDuration = results.leaseDuration;
-        p.mtu = results.mtu;
-        p.serverAddress = parcelAddress(results.serverAddress);
-        p.vendorInfo = results.vendorInfo;
-        p.serverHostName = results.serverHostName;
-        return p;
-    }
-
-    /**
-     * Convert a DhcpResultsParcelable to DhcpResults.
-     */
-    public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) {
-        if (p == null) return null;
-        final DhcpResults results = new DhcpResults(p.baseConfiguration);
-        results.leaseDuration = p.leaseDuration;
-        results.mtu = p.mtu;
-        results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress);
-        results.vendorInfo = p.vendorInfo;
-        results.serverHostName = p.serverHostName;
-        return results;
-    }
-
-    /**
-     * Convert InetAddress to String.
-     * TODO: have an InetAddressParcelable
-     */
-    public static String parcelAddress(@Nullable InetAddress addr) {
-        if (addr == null) return null;
-        return addr.getHostAddress();
-    }
-
-    /**
-     * Convert String to InetAddress.
-     * TODO: have an InetAddressParcelable
-     */
-    public static InetAddress unparcelAddress(@Nullable String addr) {
-        if (addr == null) return null;
-        return InetAddresses.parseNumericAddress(addr);
-    }
-}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
deleted file mode 100644
index 1729da6..0000000
--- a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import android.annotation.Nullable;
-import android.net.LinkProperties;
-import android.net.ProxyInfo;
-
-/**
- * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
- * and its attributes.
- * @hide
- */
-public final class LinkPropertiesParcelableUtil {
-    // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable
-    // TODO: remove the following methods after migrating clients.
-
-    /**
-     * @deprecated conversion to stable parcelable is no longer necessary.
-     */
-    @Deprecated
-    public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) {
-        return lp;
-    }
-
-    /**
-     * @deprecated conversion to stable parcelable is no longer necessary.
-     */
-    @Deprecated
-    public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) {
-        return info;
-    }
-}
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
deleted file mode 100644
index 46e9c73..0000000
--- a/services/net/java/android/net/shared/NetworkMonitorUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.shared;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-
-import android.net.NetworkCapabilities;
-
-/** @hide */
-public class NetworkMonitorUtils {
-
-    // Network conditions broadcast constants
-    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
-            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
-    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
-    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
-    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
-    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
-    public static final String EXTRA_CELL_ID = "extra_cellid";
-    public static final String EXTRA_SSID = "extra_ssid";
-    public static final String EXTRA_BSSID = "extra_bssid";
-    /** real time since boot */
-    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
-    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
-
-    /**
-     * Return whether validation is required for private DNS in strict mode.
-     * @param nc Network capabilities of the network to test.
-     */
-    public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) {
-        // TODO: Consider requiring validation for DUN networks.
-        return nc != null
-                && nc.hasCapability(NET_CAPABILITY_INTERNET)
-                && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
-                && nc.hasCapability(NET_CAPABILITY_TRUSTED);
-    }
-
-    /**
-     * Return whether validation is required for a network.
-     * @param nc Network capabilities of the network to test.
-     */
-    public static boolean isValidationRequired(NetworkCapabilities nc) {
-        // TODO: Consider requiring validation for DUN networks.
-        return isPrivateDnsValidationRequired(nc) && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
-    }
-}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
deleted file mode 100644
index 3f40300..0000000
--- a/services/net/java/android/net/shared/ParcelableUtil.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import android.annotation.NonNull;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.function.Function;
-
-/**
- * Utility methods to help convert to/from stable parcelables.
- * @hide
- */
-public final class ParcelableUtil {
-    // Below methods could be implemented easily with streams, but streams are frowned upon in
-    // frameworks code.
-
-    /**
-     * Convert a list of BaseType items to an array of ParcelableType items using the specified
-     * converter function.
-     */
-    public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
-            @NonNull Collection<BaseType> base,
-            @NonNull Function<BaseType, ParcelableType> conv,
-            @NonNull Class<ParcelableType> parcelClass) {
-        final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
-        int i = 0;
-        for (BaseType b : base) {
-            out[i] = conv.apply(b);
-            i++;
-        }
-        return out;
-    }
-
-    /**
-     * Convert an array of ParcelableType items to a list of BaseType items using the specified
-     * converter function.
-     */
-    public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
-            @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
-        final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
-        for (ParcelableType t : parceled) {
-            out.add(conv.apply(t));
-        }
-        return out;
-    }
-}
diff --git a/services/net/java/android/net/shared/PrivateDnsConfig.java b/services/net/java/android/net/shared/PrivateDnsConfig.java
deleted file mode 100644
index c7dc530..0000000
--- a/services/net/java/android/net/shared/PrivateDnsConfig.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.shared;
-
-import static android.net.shared.ParcelableUtil.fromParcelableArray;
-import static android.net.shared.ParcelableUtil.toParcelableArray;
-
-import android.net.PrivateDnsConfigParcel;
-import android.text.TextUtils;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-
-/** @hide */
-public class PrivateDnsConfig {
-    public final boolean useTls;
-    public final String hostname;
-    public final InetAddress[] ips;
-
-    public PrivateDnsConfig() {
-        this(false);
-    }
-
-    public PrivateDnsConfig(boolean useTls) {
-        this.useTls = useTls;
-        this.hostname = "";
-        this.ips = new InetAddress[0];
-    }
-
-    public PrivateDnsConfig(String hostname, InetAddress[] ips) {
-        this.useTls = !TextUtils.isEmpty(hostname);
-        this.hostname = useTls ? hostname : "";
-        this.ips = (ips != null) ? ips : new InetAddress[0];
-    }
-
-    public PrivateDnsConfig(PrivateDnsConfig cfg) {
-        useTls = cfg.useTls;
-        hostname = cfg.hostname;
-        ips = cfg.ips;
-    }
-
-    /**
-     * Indicates whether this is a strict mode private DNS configuration.
-     */
-    public boolean inStrictMode() {
-        return useTls && !TextUtils.isEmpty(hostname);
-    }
-
-    @Override
-    public String toString() {
-        return PrivateDnsConfig.class.getSimpleName()
-                + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
-    }
-
-    /**
-     * Create a stable AIDL-compatible parcel from the current instance.
-     */
-    public PrivateDnsConfigParcel toParcel() {
-        final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
-        parcel.hostname = hostname;
-        parcel.ips = toParcelableArray(
-                Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class);
-
-        return parcel;
-    }
-
-    /**
-     * Build a configuration from a stable AIDL-compatible parcel.
-     */
-    public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
-        InetAddress[] ips = new InetAddress[parcel.ips.length];
-        ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress)
-                .toArray(ips);
-        return new PrivateDnsConfig(parcel.hostname, ips);
-    }
-}
diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java
deleted file mode 100644
index 6f9c294..0000000
--- a/services/net/java/android/net/shared/ProvisioningConfiguration.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import android.annotation.Nullable;
-import android.net.INetd;
-import android.net.Network;
-import android.net.ProvisioningConfigurationParcelable;
-import android.net.StaticIpConfiguration;
-import android.net.apf.ApfCapabilities;
-import android.net.ip.IIpClient;
-
-import java.util.Objects;
-import java.util.StringJoiner;
-
-/**
- * This class encapsulates parameters to be passed to
- * IpClient#startProvisioning(). A defensive copy is made by IpClient
- * and the values specified herein are in force until IpClient#stop()
- * is called.
- *
- * Example use:
- *
- *     final ProvisioningConfiguration config =
- *             new ProvisioningConfiguration.Builder()
- *                     .withPreDhcpAction()
- *                     .withProvisioningTimeoutMs(36 * 1000)
- *                     .build();
- *     mIpClient.startProvisioning(config.toStableParcelable());
- *     ...
- *     mIpClient.stop();
- *
- * The specified provisioning configuration will only be active until
- * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
- * must specify the configuration again.
- * @hide
- */
-public class ProvisioningConfiguration {
-    // TODO: Delete this default timeout once those callers that care are
-    // fixed to pass in their preferred timeout.
-    //
-    // We pick 36 seconds so we can send DHCP requests at
-    //
-    //     t=0, t=2, t=6, t=14, t=30
-    //
-    // allowing for 10% jitter.
-    private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
-
-    /**
-     * Builder to create a {@link ProvisioningConfiguration}.
-     */
-    public static class Builder {
-        protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
-
-        /**
-         * Specify that the configuration should not enable IPv4. It is enabled by default.
-         */
-        public Builder withoutIPv4() {
-            mConfig.mEnableIPv4 = false;
-            return this;
-        }
-
-        /**
-         * Specify that the configuration should not enable IPv6. It is enabled by default.
-         */
-        public Builder withoutIPv6() {
-            mConfig.mEnableIPv6 = false;
-            return this;
-        }
-
-        /**
-         * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
-         * by default.
-         */
-        public Builder withoutMultinetworkPolicyTracker() {
-            mConfig.mUsingMultinetworkPolicyTracker = false;
-            return this;
-        }
-
-        /**
-         * Specify that the configuration should not use a IpReachabilityMonitor. It is used by
-         * default.
-         */
-        public Builder withoutIpReachabilityMonitor() {
-            mConfig.mUsingIpReachabilityMonitor = false;
-            return this;
-        }
-
-        /**
-         * Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
-         * @see #withPreDhcpAction(int)
-         */
-        public Builder withPreDhcpAction() {
-            mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
-            return this;
-        }
-
-        /**
-         * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
-         * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
-         * is disabled by default.
-         * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
-         */
-        public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
-            mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
-            return this;
-        }
-
-        /**
-         * Specify the initial provisioning configuration.
-         */
-        public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
-            mConfig.mInitialConfig = initialConfig;
-            return this;
-        }
-
-        /**
-         * Specify a static configuration for provisioning.
-         */
-        public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
-            mConfig.mStaticIpConfig = staticConfig;
-            return this;
-        }
-
-        /**
-         * Specify ApfCapabilities.
-         */
-        public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
-            mConfig.mApfCapabilities = apfCapabilities;
-            return this;
-        }
-
-        /**
-         * Specify the timeout to use for provisioning.
-         */
-        public Builder withProvisioningTimeoutMs(int timeoutMs) {
-            mConfig.mProvisioningTimeoutMs = timeoutMs;
-            return this;
-        }
-
-        /**
-         * Specify that IPv6 address generation should use a random MAC address.
-         */
-        public Builder withRandomMacAddress() {
-            mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
-            return this;
-        }
-
-        /**
-         * Specify that IPv6 address generation should use a stable MAC address.
-         */
-        public Builder withStableMacAddress() {
-            mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-            return this;
-        }
-
-        /**
-         * Specify the network to use for provisioning.
-         */
-        public Builder withNetwork(Network network) {
-            mConfig.mNetwork = network;
-            return this;
-        }
-
-        /**
-         * Specify the display name that the IpClient should use.
-         */
-        public Builder withDisplayName(String displayName) {
-            mConfig.mDisplayName = displayName;
-            return this;
-        }
-
-        /**
-         * Build the configuration using previously specified parameters.
-         */
-        public ProvisioningConfiguration build() {
-            return new ProvisioningConfiguration(mConfig);
-        }
-    }
-
-    public boolean mEnableIPv4 = true;
-    public boolean mEnableIPv6 = true;
-    public boolean mUsingMultinetworkPolicyTracker = true;
-    public boolean mUsingIpReachabilityMonitor = true;
-    public int mRequestedPreDhcpActionMs;
-    public InitialConfiguration mInitialConfig;
-    public StaticIpConfiguration mStaticIpConfig;
-    public ApfCapabilities mApfCapabilities;
-    public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
-    public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-    public Network mNetwork = null;
-    public String mDisplayName = null;
-
-    public ProvisioningConfiguration() {} // used by Builder
-
-    public ProvisioningConfiguration(ProvisioningConfiguration other) {
-        mEnableIPv4 = other.mEnableIPv4;
-        mEnableIPv6 = other.mEnableIPv6;
-        mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
-        mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
-        mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
-        mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
-        mStaticIpConfig = other.mStaticIpConfig == null
-                ? null
-                : new StaticIpConfiguration(other.mStaticIpConfig);
-        mApfCapabilities = other.mApfCapabilities;
-        mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
-        mIPv6AddrGenMode = other.mIPv6AddrGenMode;
-        mNetwork = other.mNetwork;
-        mDisplayName = other.mDisplayName;
-    }
-
-    /**
-     * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
-     */
-    public ProvisioningConfigurationParcelable toStableParcelable() {
-        final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
-        p.enableIPv4 = mEnableIPv4;
-        p.enableIPv6 = mEnableIPv6;
-        p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
-        p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
-        p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
-        p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable();
-        p.staticIpConfig = mStaticIpConfig == null
-                ? null
-                : new StaticIpConfiguration(mStaticIpConfig);
-        p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable
-        p.provisioningTimeoutMs = mProvisioningTimeoutMs;
-        p.ipv6AddrGenMode = mIPv6AddrGenMode;
-        p.network = mNetwork;
-        p.displayName = mDisplayName;
-        return p;
-    }
-
-    /**
-     * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
-     */
-    public static ProvisioningConfiguration fromStableParcelable(
-            @Nullable ProvisioningConfigurationParcelable p) {
-        if (p == null) return null;
-        final ProvisioningConfiguration config = new ProvisioningConfiguration();
-        config.mEnableIPv4 = p.enableIPv4;
-        config.mEnableIPv6 = p.enableIPv6;
-        config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
-        config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
-        config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
-        config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
-        config.mStaticIpConfig = p.staticIpConfig == null
-                ? null
-                : new StaticIpConfiguration(p.staticIpConfig);
-        config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable
-        config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
-        config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
-        config.mNetwork = p.network;
-        config.mDisplayName = p.displayName;
-        return config;
-    }
-
-    @Override
-    public String toString() {
-        return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
-                .add("mEnableIPv4: " + mEnableIPv4)
-                .add("mEnableIPv6: " + mEnableIPv6)
-                .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
-                .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
-                .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
-                .add("mInitialConfig: " + mInitialConfig)
-                .add("mStaticIpConfig: " + mStaticIpConfig)
-                .add("mApfCapabilities: " + mApfCapabilities)
-                .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
-                .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
-                .add("mNetwork: " + mNetwork)
-                .add("mDisplayName: " + mDisplayName)
-                .toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof ProvisioningConfiguration)) return false;
-        final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
-        return mEnableIPv4 == other.mEnableIPv4
-                && mEnableIPv6 == other.mEnableIPv6
-                && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
-                && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
-                && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
-                && Objects.equals(mInitialConfig, other.mInitialConfig)
-                && Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
-                && Objects.equals(mApfCapabilities, other.mApfCapabilities)
-                && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
-                && mIPv6AddrGenMode == other.mIPv6AddrGenMode
-                && Objects.equals(mNetwork, other.mNetwork)
-                && Objects.equals(mDisplayName, other.mDisplayName);
-    }
-
-    public boolean isValid() {
-        return (mInitialConfig == null) || mInitialConfig.isValid();
-    }
-}
diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java
deleted file mode 100644
index f6bb873..0000000
--- a/services/net/java/android/net/util/InterfaceParams.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static com.android.internal.util.Preconditions.checkArgument;
-
-import android.net.MacAddress;
-import android.text.TextUtils;
-
-import java.net.NetworkInterface;
-import java.net.SocketException;
-
-
-/**
- * Encapsulate the interface parameters common to IpClient/IpServer components.
- *
- * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient
- * and IpServer (sub)components need most or all of this information at some
- * point during their lifecycles, so pass only this simplified object around
- * which can be created once when IpClient/IpServer are told to start.
- *
- * @hide
- */
-public class InterfaceParams {
-    public final String name;
-    public final int index;
-    public final MacAddress macAddr;
-    public final int defaultMtu;
-
-    // TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack.
-    private static final int ETHER_MTU = 1500;
-    private static final int IPV6_MIN_MTU = 1280;
-
-
-    public static InterfaceParams getByName(String name) {
-        final NetworkInterface netif = getNetworkInterfaceByName(name);
-        if (netif == null) return null;
-
-        // Not all interfaces have MAC addresses, e.g. rmnet_data0.
-        final MacAddress macAddr = getMacAddress(netif);
-
-        try {
-            return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU());
-        } catch (IllegalArgumentException|SocketException e) {
-            return null;
-        }
-    }
-
-    public InterfaceParams(String name, int index, MacAddress macAddr) {
-        this(name, index, macAddr, ETHER_MTU);
-    }
-
-    public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) {
-        checkArgument((!TextUtils.isEmpty(name)), "impossible interface name");
-        checkArgument((index > 0), "invalid interface index");
-        this.name = name;
-        this.index = index;
-        this.macAddr = (macAddr != null) ? macAddr : MacAddress.fromBytes(new byte[] {
-                0x02, 0x00, 0x00, 0x00, 0x00, 0x00 });
-        this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU;
-    }
-
-    @Override
-    public String toString() {
-        return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu);
-    }
-
-    private static NetworkInterface getNetworkInterfaceByName(String name) {
-        try {
-            return NetworkInterface.getByName(name);
-        } catch (NullPointerException|SocketException e) {
-            return null;
-        }
-    }
-
-    private static MacAddress getMacAddress(NetworkInterface netif) {
-        try {
-            return MacAddress.fromBytes(netif.getHardwareAddress());
-        } catch (IllegalArgumentException|NullPointerException|SocketException e) {
-            return null;
-        }
-    }
-}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
deleted file mode 100644
index 2cdb2b0..0000000
--- a/services/net/java/android/net/util/SharedLog.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.StringJoiner;
-
-
-/**
- * Class to centralize logging functionality for tethering.
- *
- * All access to class methods other than dump() must be on the same thread.
- *
- * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
- * @hide
- */
-public class SharedLog {
-    private static final int DEFAULT_MAX_RECORDS = 500;
-    private static final String COMPONENT_DELIMITER = ".";
-
-    private enum Category {
-        NONE,
-        ERROR,
-        MARK,
-        WARN,
-    };
-
-    private final LocalLog mLocalLog;
-    // The tag to use for output to the system log. This is not output to the
-    // LocalLog because that would be redundant.
-    private final String mTag;
-    // The component (or subcomponent) of a system that is sharing this log.
-    // This can grow in depth if components call forSubComponent() to obtain
-    // their SharedLog instance. The tag is not included in the component for
-    // brevity.
-    private final String mComponent;
-
-    public SharedLog(String tag) {
-        this(DEFAULT_MAX_RECORDS, tag);
-    }
-
-    public SharedLog(int maxRecords, String tag) {
-        this(new LocalLog(maxRecords), tag, tag);
-    }
-
-    private SharedLog(LocalLog localLog, String tag, String component) {
-        mLocalLog = localLog;
-        mTag = tag;
-        mComponent = component;
-    }
-
-    public String getTag() {
-        return mTag;
-    }
-
-    /**
-     * Create a SharedLog based on this log with an additional component prefix on each logged line.
-     */
-    public SharedLog forSubComponent(String component) {
-        if (!isRootLogInstance()) {
-            component = mComponent + COMPONENT_DELIMITER + component;
-        }
-        return new SharedLog(mLocalLog, mTag, component);
-    }
-
-    /**
-     * Dump the contents of this log.
-     *
-     * <p>This method may be called on any thread.
-     */
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
-    }
-
-    //////
-    // Methods that both log an entry and emit it to the system log.
-    //////
-
-    /**
-     * Log an error due to an exception. This does not include the exception stacktrace.
-     *
-     * <p>The log entry will be also added to the system log.
-     * @see #e(String, Throwable)
-     */
-    public void e(Exception e) {
-        Log.e(mTag, record(Category.ERROR, e.toString()));
-    }
-
-    /**
-     * Log an error message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void e(String msg) {
-        Log.e(mTag, record(Category.ERROR, msg));
-    }
-
-    /**
-     * Log an error due to an exception, with the exception stacktrace if provided.
-     *
-     * <p>The error and exception message appear in the shared log, but the stacktrace is only
-     * logged in general log output (logcat). The log entry will be also added to the system log.
-     */
-    public void e(@NonNull String msg, @Nullable Throwable exception) {
-        if (exception == null) {
-            e(msg);
-            return;
-        }
-        Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
-    }
-
-    /**
-     * Log an informational message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void i(String msg) {
-        Log.i(mTag, record(Category.NONE, msg));
-    }
-
-    /**
-     * Log a warning message.
-     *
-     * <p>The log entry will be also added to the system log.
-     */
-    public void w(String msg) {
-        Log.w(mTag, record(Category.WARN, msg));
-    }
-
-    //////
-    // Methods that only log an entry (and do NOT emit to the system log).
-    //////
-
-    /**
-     * Log a general message to be only included in the in-memory log.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     */
-    public void log(String msg) {
-        record(Category.NONE, msg);
-    }
-
-    /**
-     * Log a general, formatted message to be only included in the in-memory log.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     * @see String#format(String, Object...)
-     */
-    public void logf(String fmt, Object... args) {
-        log(String.format(fmt, args));
-    }
-
-    /**
-     * Log a message with MARK level.
-     *
-     * <p>The log entry will *not* be added to the system log.
-     */
-    public void mark(String msg) {
-        record(Category.MARK, msg);
-    }
-
-    private String record(Category category, String msg) {
-        final String entry = logLine(category, msg);
-        mLocalLog.log(entry);
-        return entry;
-    }
-
-    private String logLine(Category category, String msg) {
-        final StringJoiner sj = new StringJoiner(" ");
-        if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
-        if (category != Category.NONE) sj.add(category.toString());
-        return sj.add(msg).toString();
-    }
-
-    // Check whether this SharedLog instance is nominally the top level in
-    // a potential hierarchy of shared logs (the root of a tree),
-    // or is a subcomponent within the hierarchy.
-    private boolean isRootLogInstance() {
-        return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index e9e96c9..8fd8d04 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,6 +56,7 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
 import android.net.wifi.WifiSsid;
 import android.os.Binder;
 import android.os.Handler;
@@ -719,7 +720,7 @@
 
     @Test
     public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception {
-        when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE);
+        when(mWifiInfo.getSSID()).thenReturn(WifiManager.UNKNOWN_SSID);
         NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter =
                 new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo);
 
@@ -793,7 +794,7 @@
         List<ScanResult> invalidScanResults = Lists.newArrayList(
                 new ScanResult(),
                 createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid),
-                createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid),
+                createScanResult(WifiManager.UNKNOWN_SSID, SCORED_NETWORK.networkKey.wifiKey.bssid),
                 createScanResult(SSID, null),
                 createScanResult(SSID, INVALID_BSSID)
         );
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
new file mode 100644
index 0000000..470d4fa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.PackageParser;
+
+import com.android.internal.util.ArrayUtils;
+
+class PackageBuilder {
+    final PackageParser.Package mPkg;
+
+    PackageBuilder(String packageName) {
+        mPkg = new PackageParser.Package(packageName);
+    }
+
+    PackageBuilder setApplicationInfoCodePath(String codePath) {
+        mPkg.applicationInfo.setCodePath(codePath);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
+        mPkg.applicationInfo.setResourcePath(resourcePath);
+        return this;
+    }
+
+    PackageBuilder setCodePath(String codePath) {
+        mPkg.codePath = codePath;
+        return this;
+    }
+
+    PackageBuilder setBaseCodePath(String baseCodePath) {
+        mPkg.baseCodePath = baseCodePath;
+        return this;
+    }
+
+    PackageBuilder addUsesStaticLibrary(String name, long version) {
+        mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
+        mPkg.usesStaticLibrariesVersions =
+                ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
+        mPkg.applicationInfo.nativeLibraryRootDir = dir;
+        return this;
+    }
+
+    PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
+        mPkg.staticSharedLibVersion = staticSharedLibVersion;
+        mPkg.staticSharedLibName = staticSharedLibName;
+        return this;
+    }
+
+    PackageBuilder setManifestPackageName(String manifestPackageName) {
+        mPkg.manifestPackageName = manifestPackageName;
+        return this;
+    }
+
+    PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
+        mPkg.mVersionCodeMajor = versionCodeMajor;
+        return this;
+    }
+
+    PackageBuilder setVersionCode(int versionCode) {
+        mPkg.mVersionCode = versionCode;
+        return this;
+    }
+
+    PackageBuilder addSplitCodePath(String splitCodePath) {
+        mPkg.splitCodePaths =
+                ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
+        mPkg.applicationInfo.volumeUuid = volumeUuid;
+        return this;
+    }
+
+    PackageBuilder addLibraryName(String libraryName) {
+        mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
+        return this;
+    }
+
+    PackageBuilder setRealPackageName(String realPackageName) {
+        mPkg.mRealPackage = realPackageName;
+        return this;
+    }
+
+    PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
+        mPkg.cpuAbiOverride = cpuAbiOverride;
+        return this;
+    }
+
+    PackageBuilder addPermissionRequest(String permissionName) {
+        mPkg.requestedPermissions.add(permissionName);
+        return this;
+    }
+
+    PackageParser.Package build() {
+        return mPkg;
+    }
+
+    public PackageBuilder addApplicationInfoFlag(int flag) {
+        mPkg.applicationInfo.flags |= flag;
+        return this;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
new file mode 100644
index 0000000..b42cfd8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.PackageUserState;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.util.List;
+
+class PackageSettingBuilder {
+    private String mName;
+    private String mRealName;
+    private String mCodePath;
+    private String mResourcePath;
+    private String mLegacyNativeLibraryPathString;
+    private String mPrimaryCpuAbiString;
+    private String mSecondaryCpuAbiString;
+    private String mCpuAbiOverrideString;
+    private long mPVersionCode;
+    private int mPkgFlags;
+    private int mPrivateFlags;
+    private String mParentPackageName;
+    private List<String> mChildPackageNames;
+    private int mSharedUserId;
+    private String[] mUsesStaticLibraries;
+    private long[] mUsesStaticLibrariesVersions;
+    private String mVolumeUuid;
+    private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+
+    public PackageSettingBuilder setName(String name) {
+        this.mName = name;
+        return this;
+    }
+
+    public PackageSettingBuilder setRealName(String realName) {
+        this.mRealName = realName;
+        return this;
+    }
+
+    public PackageSettingBuilder setCodePath(String codePath) {
+        this.mCodePath = codePath;
+        return this;
+    }
+
+    public PackageSettingBuilder setResourcePath(String resourcePath) {
+        this.mResourcePath = resourcePath;
+        return this;
+    }
+
+    public PackageSettingBuilder setLegacyNativeLibraryPathString(
+            String legacyNativeLibraryPathString) {
+        this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
+        return this;
+    }
+
+    public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
+        this.mPrimaryCpuAbiString = primaryCpuAbiString;
+        return this;
+    }
+
+    public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
+        this.mSecondaryCpuAbiString = secondaryCpuAbiString;
+        return this;
+    }
+
+    public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
+        this.mCpuAbiOverrideString = cpuAbiOverrideString;
+        return this;
+    }
+
+    public PackageSettingBuilder setPVersionCode(long pVersionCode) {
+        this.mPVersionCode = pVersionCode;
+        return this;
+    }
+
+    public PackageSettingBuilder setPkgFlags(int pkgFlags) {
+        this.mPkgFlags = pkgFlags;
+        return this;
+    }
+
+    public PackageSettingBuilder setPrivateFlags(int privateFlags) {
+        this.mPrivateFlags = privateFlags;
+        return this;
+    }
+
+    public PackageSettingBuilder setParentPackageName(String parentPackageName) {
+        this.mParentPackageName = parentPackageName;
+        return this;
+    }
+
+    public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
+        this.mChildPackageNames = childPackageNames;
+        return this;
+    }
+
+    public PackageSettingBuilder setSharedUserId(int sharedUserId) {
+        this.mSharedUserId = sharedUserId;
+        return this;
+    }
+
+    public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
+        this.mUsesStaticLibraries = usesStaticLibraries;
+        return this;
+    }
+
+    public PackageSettingBuilder setUsesStaticLibrariesVersions(
+            long[] usesStaticLibrariesVersions) {
+        this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
+        return this;
+    }
+
+    public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
+        this.mVolumeUuid = volumeUuid;
+        return this;
+    }
+
+    public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
+        if (mUserStates.indexOfKey(userId) < 0) {
+            mUserStates.put(userId, new PackageUserState());
+        }
+        mUserStates.get(userId).instantApp = isInstant;
+        return this;
+    }
+
+    public PackageSetting build() {
+        final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
+                new File(mCodePath), new File(mResourcePath),
+                mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
+                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
+                mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
+                mUsesStaticLibrariesVersions);
+        packageSetting.volumeUuid = this.mVolumeUuid;
+        for (int i = 0; i < mUserStates.size(); i++) {
+            packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
+        }
+        return packageSetting;
+
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
new file mode 100644
index 0000000..34a3f86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+
+class ScanRequestBuilder {
+    private final PackageParser.Package mPkg;
+    private PackageParser.Package mOldPkg;
+    private SharedUserSetting mSharedUserSetting;
+    private PackageSetting mPkgSetting;
+    private PackageSetting mDisabledPkgSetting;
+    private PackageSetting mOriginalPkgSetting;
+    private String mRealPkgName;
+    private int mParseFlags;
+    private int mScanFlags;
+    private UserHandle mUser;
+    private boolean mIsPlatformPackage;
+
+    ScanRequestBuilder(PackageParser.Package pkg) {
+        this.mPkg = pkg;
+    }
+
+    public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+        this.mOldPkg = oldPkg;
+        return this;
+    }
+
+    public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
+        this.mSharedUserSetting = sharedUserSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
+        this.mPkgSetting = pkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
+        this.mDisabledPkgSetting = disabledPkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
+        this.mOriginalPkgSetting = originalPkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setRealPkgName(String realPkgName) {
+        this.mRealPkgName = realPkgName;
+        return this;
+    }
+
+    public ScanRequestBuilder setParseFlags(int parseFlags) {
+        this.mParseFlags = parseFlags;
+        return this;
+    }
+
+    public ScanRequestBuilder addParseFlag(int parseFlag) {
+        this.mParseFlags |= parseFlag;
+        return this;
+    }
+
+    public ScanRequestBuilder setScanFlags(int scanFlags) {
+        this.mScanFlags = scanFlags;
+        return this;
+    }
+
+    public ScanRequestBuilder addScanFlag(int scanFlag) {
+        this.mScanFlags |= scanFlag;
+        return this;
+    }
+
+    public ScanRequestBuilder setUser(UserHandle user) {
+        this.mUser = user;
+        return this;
+    }
+
+    public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
+        this.mIsPlatformPackage = isPlatformPackage;
+        return this;
+    }
+
+    PackageManagerService.ScanRequest build() {
+        return new PackageManagerService.ScanRequest(
+                mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
+                mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
+                mUser);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
new file mode 100644
index 0000000..dd3d8b9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
+import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
+import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+// TODO: shared user tests
+public class ScanTests {
+
+    private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+
+    @Mock
+    PackageAbiHelper mMockPackageAbiHelper;
+    @Mock
+    UserManagerInternal mMockUserManager;
+
+    @Before
+    public void setupDefaultUser() {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+    }
+
+    @Before
+    public void setupDefaultAbiBehavior() throws Exception {
+        when(mMockPackageAbiHelper.derivePackageAbi(
+                any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+                .thenReturn(new Pair<>(
+                        new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
+                        new PackageAbiHelper.NativeLibraryPaths(
+                                "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
+        when(mMockPackageAbiHelper.getNativeLibraryPaths(
+                any(PackageParser.Package.class), any(File.class)))
+                .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
+                        "getRootDir", true, "getNativeDir", "getNativeDir2"
+                ));
+        when(mMockPackageAbiHelper.getBundledAppAbis(
+                any(PackageParser.Package.class)))
+                .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
+    }
+
+    @Test
+    public void newInstallSimpleAllNominal() throws Exception {
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+        assertThat(scanResult.existingSettingCopied, is(false));
+        assertPathsNotDerived(scanResult);
+    }
+
+    @Test
+    public void newInstallForAllUsers() throws Exception {
+        final int[] userIds = {0, 10, 11};
+        when(mMockUserManager.getUserIds()).thenReturn(userIds);
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setRealPkgName(null)
+                        .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+                        .build();
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        for (int uid : userIds) {
+            assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+        }
+    }
+
+    @Test
+    public void installRealPackageName() throws Exception {
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setRealPkgName("com.package.real")
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+
+        final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+                createBasicScanRequestBuilder(
+                        createBasicPackage(DUMMY_PACKAGE_NAME)
+                                .setRealPackageName("com.package.real").build())
+                        .build();
+
+        final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+        assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+    }
+
+    @Test
+    public void updateSimpleNominal() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                .setPrimaryCpuAbiString("primaryCpuAbi")
+                .setSecondaryCpuAbiString("secondaryCpuAbi")
+                .build();
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+                        .setPkgSetting(pkgSetting)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.existingSettingCopied, is(true));
+
+        // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
+        assertNotSame(pkgSetting, scanResult.pkgSetting);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+
+        assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+        assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+        assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+
+        assertPathsNotDerived(scanResult);
+    }
+
+    @Test
+    public void updateInstantSimpleNominal() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, true)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+    }
+
+    @Test
+    public void installStaticSharedLibrary() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
+                .setStaticSharedLib("static.lib", 123L)
+                .setManifestPackageName("static.lib.pkg")
+                .setVersionCodeMajor(1)
+                .setVersionCode(234)
+                .setBaseCodePath("/some/path.apk")
+                .addSplitCodePath("/some/other/path.apk")
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
+                pkg).setUser(UserHandle.of(0)).build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+        assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
+        assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
+        assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+                is("static.lib.pkg"));
+        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
+        assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+    }
+
+    @Test
+    public void installDynamicLibraries() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
+                .setManifestPackageName("dynamic.lib.pkg")
+                .addLibraryName("liba")
+                .addLibraryName("libb")
+                .setVersionCodeMajor(1)
+                .setVersionCode(234)
+                .setBaseCodePath("/some/path.apk")
+                .addSplitCodePath("/some/other/path.apk")
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+        assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib0.getName(), is("liba"));
+        assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
+        assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
+        assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(dynamicLib0.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(dynamicLib0.getDependencies(), nullValue());
+        assertThat(dynamicLib0.getDependentPackages(), empty());
+
+        final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+        assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib1.getName(), is("libb"));
+        assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
+        assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
+        assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(dynamicLib1.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(dynamicLib1.getDependencies(), nullValue());
+        assertThat(dynamicLib1.getDependentPackages(), empty());
+    }
+
+    @Test
+    public void volumeUuidChangesOnUpdate() throws Exception {
+        final PackageSetting pkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setVolumeUuid("someUuid")
+                        .build();
+
+        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .setApplicationInfoVolumeUuid("someNewUuid")
+                .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(
+                new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
+
+        assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+    }
+
+    @Test
+    public void scanFirstBoot_derivesAbis() throws Exception {
+        final PackageSetting pkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
+
+        final PackageParser.Package basicPackage =
+                createBasicPackage(DUMMY_PACKAGE_NAME)
+                        .setCpuAbiOVerride("testOverride")
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+                basicPackage)
+                .setPkgSetting(pkgSetting)
+                .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
+                .build());
+
+        assertAbiAndPathssDerived(scanResult);
+    }
+
+    @Test
+    public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
+        final PackageSetting originalPkgSetting =
+                createBasicPackageSettingBuilder("original.package").build();
+
+        final PackageParser.Package basicPackage =
+                createBasicPackage(DUMMY_PACKAGE_NAME)
+                        .build();
+
+
+        final PackageManagerService.ScanResult result =
+                executeScan(new ScanRequestBuilder(basicPackage)
+                        .setOriginalPkgSetting(originalPkgSetting)
+                        .build());
+
+        assertThat(result.request.pkg.packageName, is("original.package"));
+    }
+
+    @Test
+    public void updateInstant_changeToFull() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, true)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_AS_FULL_APP)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+    }
+
+    @Test
+    public void updateFull_changeToInstant() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, false)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_AS_INSTANT_APP)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+    }
+
+    @Test
+    public void updateSystemApp_applicationInfoFlagSet() throws Exception {
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .setDisabledPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_NEW_INSTALL)
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.request.pkg.applicationInfo.flags,
+                hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+    }
+
+    @Test
+    public void factoryTestFlagSet() throws Exception {
+        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addPermissionRequest(Manifest.permission.FACTORY_TEST)
+                .build();
+
+        final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+                createBasicScanRequestBuilder(basicPackage).build(),
+                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                true /*isUnderFactoryTest*/,
+                System.currentTimeMillis());
+
+        assertThat(scanResult.request.pkg.applicationInfo.flags,
+                hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+    }
+
+    @Test
+    public void scanSystemApp_isOrphanedTrue() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(pkg)
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.pkgSetting.isOrphaned, is(true));
+    }
+
+    private static Matcher<Integer> hasFlag(final int flag) {
+        return new BaseMatcher<Integer>() {
+            @Override public void describeTo(Description description) {
+                description.appendText("flags ");
+            }
+
+            @Override public boolean matches(Object item) {
+                return ((int) item & flag) != 0;
+            }
+
+            @Override
+            public void describeMismatch(Object item, Description mismatchDescription) {
+                mismatchDescription
+                        .appendValue(item)
+                        .appendText(" does not contain flag ")
+                        .appendValue(flag);
+            }
+        };
+    }
+
+    private PackageManagerService.ScanResult executeScan(
+            PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
+        return PackageManagerService.scanPackageOnlyLI(
+                scanRequest,
+                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                false /*isUnderFactoryTest*/,
+                System.currentTimeMillis());
+    }
+
+    private static String createResourcePath(String packageName) {
+        return "/data/app/" + packageName + "-randompath/base.apk";
+    }
+
+    private static String createCodePath(String packageName) {
+        return "/data/app/" + packageName + "-randompath";
+    }
+
+    private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
+        return new PackageSettingBuilder()
+                .setName(packageName)
+                .setCodePath(createCodePath(packageName))
+                .setResourcePath(createResourcePath(packageName));
+    }
+
+    private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+        return new ScanRequestBuilder(pkg)
+                .setUser(UserHandle.of(0));
+    }
+
+
+    private static PackageBuilder createBasicPackage(String packageName) {
+        return new PackageBuilder(packageName)
+                .setCodePath("/data/tmp/randompath")
+                .setApplicationInfoCodePath(createCodePath(packageName))
+                .setApplicationInfoResourcePath(createResourcePath(packageName))
+                .setApplicationInfoVolumeUuid("volumeUuid")
+                .setBaseCodePath("/data/tmp/randompath/base.apk")
+                .addUsesStaticLibrary("some.static.library", 234L)
+                .addUsesStaticLibrary("some.other.static.library", 456L)
+                .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+                .setVersionCodeMajor(1)
+                .setVersionCode(2345);
+    }
+
+    private static void assertBasicPackageScanResult(
+            PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
+        assertThat(scanResult.success, is(true));
+
+        final PackageSetting pkgSetting = scanResult.pkgSetting;
+        assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
+
+        final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+        assertBasicApplicationInfo(scanResult, applicationInfo);
+
+    }
+
+    private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+            String packageName, boolean isInstant, PackageSetting pkgSetting) {
+        assertThat(pkgSetting.pkg.packageName, is(packageName));
+        assertThat(pkgSetting.getInstantApp(0), is(isInstant));
+        assertThat(pkgSetting.usesStaticLibraries,
+                arrayContaining("some.static.library", "some.other.static.library"));
+        assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
+        assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
+        assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+        assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
+        assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
+        assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
+    }
+
+    private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+            ApplicationInfo applicationInfo) {
+        assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+
+        final int uid = applicationInfo.uid;
+        assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
+
+        final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
+                applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
+                scanResult.request.pkg.packageName).getAbsolutePath();
+        assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
+        assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
+    }
+
+    private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
+        assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
+
+        assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
+        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+        assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
+        assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
+    }
+
+    private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
+        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
+        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
+        assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
+        assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
new file mode 100644
index 0000000..1f312bf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IRecoverySystemProgressListener;
+import android.os.Looper;
+import android.os.PowerManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileWriter;
+
+/**
+ * atest FrameworksServicesTests:RecoverySystemServiceTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverySystemServiceTest {
+    private RecoverySystemService mRecoverySystemService;
+    private RecoverySystemServiceTestable.FakeSystemProperties mSystemProperties;
+    private RecoverySystemService.UncryptSocket mUncryptSocket;
+    private Context mContext;
+    private IPowerManager mIPowerManager;
+    private FileWriter mUncryptUpdateFileWriter;
+
+    @Before
+    public void setup() {
+        mContext = mock(Context.class);
+        mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
+        mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
+        mUncryptUpdateFileWriter = mock(FileWriter.class);
+
+        Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        mIPowerManager = mock(IPowerManager.class);
+        PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
+                new Handler(looper));
+
+        mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
+                powerManager, mUncryptUpdateFileWriter, mUncryptSocket);
+    }
+
+    @Test
+    public void clearBcb_success() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+        assertThat(mRecoverySystemService.clearBcb(), is(true));
+
+        assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+    }
+
+    @Test
+    public void clearBcb_uncrypt_failure() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+        assertThat(mRecoverySystemService.clearBcb(), is(false));
+
+        assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+    }
+
+    @Test(expected = SecurityException.class)
+    public void clearBcb_noPerm() {
+        doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        mRecoverySystemService.clearBcb();
+    }
+
+    @Test
+    public void setupBcb_success() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+        assertThat(mRecoverySystemService.setupBcb("foo"), is(true));
+
+        assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+        verify(mUncryptSocket).sendCommand("foo");
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+    }
+
+    @Test
+    public void setupBcb_uncrypt_failure() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+        assertThat(mRecoverySystemService.setupBcb("foo"), is(false));
+
+        assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+        verify(mUncryptSocket).sendCommand("foo");
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+    }
+
+    @Test(expected = SecurityException.class)
+    public void setupBcb_noPerm() {
+        doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        mRecoverySystemService.setupBcb("foo");
+    }
+
+    @Test
+    public void rebootRecoveryWithCommand_success() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+        mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+        assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+        verify(mUncryptSocket).sendCommand("foo");
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+        verify(mIPowerManager).reboot(anyBoolean(), eq("recovery"), anyBoolean());
+    }
+
+    @Test
+    public void rebootRecoveryWithCommand_failure() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+        mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+        assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+        verify(mUncryptSocket).sendCommand("foo");
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+        verifyNoMoreInteractions(mIPowerManager);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void rebootRecoveryWithCommand_noPerm() {
+        doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        mRecoverySystemService.rebootRecoveryWithCommand("foo");
+    }
+
+    @Test
+    public void uncrypt_success() throws Exception {
+        doNothing().when(mContext).enforceCallingOrSelfPermission(
+                eq(android.Manifest.permission.RECOVERY), any());
+        when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0, 5, 25, 50, 90, 99, 100);
+
+        IRecoverySystemProgressListener listener = mock(IRecoverySystemProgressListener.class);
+        assertThat(mRecoverySystemService.uncrypt("foo.zip", listener), is(true));
+
+        assertThat(mSystemProperties.getCtlStart(), is("uncrypt"));
+        verify(mUncryptSocket, times(7)).getPercentageUncrypted();
+        verify(mUncryptSocket).sendAck();
+        verify(mUncryptSocket).close();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
new file mode 100644
index 0000000..a986b71
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+import java.io.FileWriter;
+
+public class RecoverySystemServiceTestable extends RecoverySystemService {
+    private static class MockInjector extends RecoverySystemService.Injector {
+        private final FakeSystemProperties mSystemProperties;
+        private final PowerManager mPowerManager;
+        private final FileWriter mUncryptPackageFileWriter;
+        private final UncryptSocket mUncryptSocket;
+
+        MockInjector(Context context, FakeSystemProperties systemProperties,
+                PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+                UncryptSocket uncryptSocket) {
+            super(context);
+            mSystemProperties = systemProperties;
+            mPowerManager = powerManager;
+            mUncryptPackageFileWriter = uncryptPackageFileWriter;
+            mUncryptSocket = uncryptSocket;
+        }
+
+        @Override
+        public PowerManager getPowerManager() {
+            return mPowerManager;
+        }
+
+        @Override
+        public String systemPropertiesGet(String key) {
+            return mSystemProperties.get(key);
+        }
+
+        @Override
+        public void systemPropertiesSet(String key, String value) {
+            mSystemProperties.set(key, value);
+        }
+
+        @Override
+        public boolean uncryptPackageFileDelete() {
+            return true;
+        }
+
+        @Override
+        public String getUncryptPackageFileName() {
+            return "mock-file.txt";
+        }
+
+        @Override
+        public FileWriter getUncryptPackageFileWriter() {
+            return mUncryptPackageFileWriter;
+        }
+
+        @Override
+        public UncryptSocket connectService() {
+            return mUncryptSocket;
+        }
+
+        @Override
+        public void threadSleep(long millis) {
+        }
+    }
+
+    RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
+            PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+            UncryptSocket uncryptSocket) {
+        super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
+                uncryptSocket));
+    }
+
+    public static class FakeSystemProperties {
+        private String mCtlStart = null;
+
+        public String get(String key) {
+            if (RecoverySystemService.INIT_SERVICE_UNCRYPT.equals(key)
+                    || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
+                    || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
+                return null;
+            } else {
+                throw new IllegalArgumentException("unexpected test key: " + key);
+            }
+        }
+
+        public void set(String key, String value) {
+            if ("ctl.start".equals(key)) {
+                mCtlStart = value;
+            } else {
+                throw new IllegalArgumentException("unexpected test key: " + key);
+            }
+        }
+
+        public String getCtlStart() {
+            return mCtlStart;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 7986055..8cb5197 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -58,8 +59,8 @@
         // All users are unlocked so we should snapshot data for them.
         doReturn(true).when(helper).isUserCredentialLocked(eq(10));
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
-        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
-        helper.snapshotAppData(5, info);
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+        helper.snapshotAppData(5, info, new int[]{10, 11});
 
         assertEquals(2, info.getPendingBackups().size());
         assertEquals(10, info.getPendingBackups().get(0));
@@ -79,8 +80,8 @@
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
         when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
 
-        PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
-        helper.snapshotAppData(7, info2);
+        PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar");
+        helper.snapshotAppData(7, info2, new int[]{10, 11});
         assertEquals(1, info2.getPendingBackups().size());
         assertEquals(11, info2.getPendingBackups().get(0));
 
@@ -234,22 +235,22 @@
         wasRecentlyRestored.getPendingRestores().add(
                 new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
 
-        RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1);
+        Rollback dataWithPendingBackup = new Rollback(101, new File("/does/not/exist"), -1);
         dataWithPendingBackup.info.getPackages().add(pendingBackup);
 
-        RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"),
+        Rollback dataWithRecentRestore = new Rollback(17239, new File("/does/not/exist"),
                 -1);
         dataWithRecentRestore.info.getPackages().add(wasRecentlyRestored);
 
-        RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"),
+        Rollback dataForDifferentUser = new Rollback(17239, new File("/does/not/exist"),
                 -1);
         dataForDifferentUser.info.getPackages().add(ignoredInfo);
 
-        RollbackData dataForRestore = new RollbackData(17239, new File("/does/not/exist"), -1);
+        Rollback dataForRestore = new Rollback(17239, new File("/does/not/exist"), -1);
         dataForRestore.info.getPackages().add(pendingRestore);
         dataForRestore.info.getPackages().add(wasRecentlyRestored);
 
-        Set<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37,
+        Set<Rollback> changed = helper.commitPendingBackupAndRestoreForUser(37,
                 Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser,
                     dataForRestore));
         InOrder inOrder = Mockito.inOrder(installer);
@@ -264,7 +265,7 @@
         assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
         assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
 
-        // Check that changed returns correct RollbackData.
+        // Check that changed returns correct Rollback.
         assertEquals(3, changed.size());
         assertTrue(changed.contains(dataWithPendingBackup));
         assertTrue(changed.contains(dataWithRecentRestore));
@@ -278,4 +279,15 @@
 
         inOrder.verifyNoMoreInteractions();
     }
+
+    @Test
+    public void snapshotAddDataSavesSnapshottedUsersToInfo() {
+        Installer installer = mock(Installer.class);
+        AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
+
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+        helper.snapshotAppData(5, info, new int[]{10, 11});
+
+        assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11});
+    }
 }
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index d669e905..58abf00 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.telecom.Connection.VideoProvider;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index e2f5d0bb..4c22ba9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -35,6 +35,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index ae92464..bebbbd0 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -97,6 +97,14 @@
      */
     public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
 
+    /**
+     * This reason is set when a call is ended in order to place an emergency call when a
+     * {@link PhoneAccount} doesn't support holding an ongoing call to place an emergency call. This
+     * reason string should only be associated with the {@link #LOCAL} disconnect code returned from
+     * {@link #getCode()}.
+     */
+    public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
+
     private int mDisconnectCode;
     private CharSequence mDisconnectLabel;
     private CharSequence mDisconnectDescription;
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/GsmAlphabet.java
rename to telephony/common/com/android/internal/telephony/GsmAlphabet.java
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index f79aef3..9da45da 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -195,7 +195,7 @@
      * @return
      */
     private static int getIncomingUserId(Context context) {
-        int contextUserId = context.getUserId();
+        int contextUserId = UserHandle.myUserId();
         final int callingUid = Binder.getCallingUid();
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index a884a70..72f758e 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -469,4 +469,44 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface DataFailureCause {
     }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"PRECISE_CALL_STATE_"},
+            value = {
+            PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+            PreciseCallState.PRECISE_CALL_STATE_IDLE,
+            PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
+            PreciseCallState.PRECISE_CALL_STATE_HOLDING,
+            PreciseCallState.PRECISE_CALL_STATE_DIALING,
+            PreciseCallState.PRECISE_CALL_STATE_ALERTING,
+            PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+            PreciseCallState.PRECISE_CALL_STATE_WAITING,
+            PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
+            PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
+    public @interface PreciseCallStates {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RIL_RADIO_TECHNOLOGY_" }, value = {
+            ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN,
+            ServiceState.RIL_RADIO_TECHNOLOGY_GPRS,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EDGE,
+            ServiceState.RIL_RADIO_TECHNOLOGY_UMTS,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IS95A,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IS95B,
+            ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD,
+            ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP,
+            ServiceState.RIL_RADIO_TECHNOLOGY_GSM,
+            ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+            ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_NR})
+    public @interface RilRadioTechnology {}
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c0e03a7..a0aa892 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1745,6 +1745,15 @@
             "allow_emergency_video_calls_bool";
 
     /**
+     * Flag indicating whether or not an ongoing call will be held when an outgoing emergency call
+     * is placed. If true, ongoing calls will be put on hold when an emergency call is placed. If
+     * false, placing an emergency call will trigger the disconnect of all ongoing calls before
+     * the emergency call is placed.
+     */
+    public static final String KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL =
+            "allow_hold_call_during_emergency_bool";
+
+    /**
      * Flag indicating whether the carrier supports RCS presence indication for
      * User Capability Exchange (UCE).  When presence is supported, the device should use the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
@@ -3501,6 +3510,7 @@
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
         sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0);
+        sDefaults.putBoolean(KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
         sDefaults.putBoolean(KEY_USE_RCS_SIP_OPTIONS_BOOL, false);
         sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
diff --git a/telephony/java/com/android/internal/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
similarity index 94%
rename from telephony/java/com/android/internal/telephony/CbGeoUtils.java
rename to telephony/java/android/telephony/CbGeoUtils.java
index 0b73252..f4ce6e7 100644
--- a/telephony/java/com/android/internal/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony;
+package android.telephony;
 
 import android.annotation.NonNull;
-import android.telephony.Rlog;
+import android.annotation.SystemApi;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -30,8 +30,17 @@
  * The coordinates used by this utils class are latitude and longitude, but some algorithms in this
  * class only use them as coordinates on plane, so the calculation will be inaccurate. So don't use
  * this class for anything other then geo-targeting of cellbroadcast messages.
+ * @hide
  */
+@SystemApi
 public class CbGeoUtils {
+
+    /**
+     * This class is never instantiated
+     * @hide
+     */
+    private CbGeoUtils() {}
+
     /** Geometric interface. */
     public interface Geometry {
         /**
@@ -39,27 +48,36 @@
          * @param p point in latitude, longitude format.
          * @return {@code True} if the given point is inside the geometry.
          */
-        boolean contains(LatLng p);
+        boolean contains(@NonNull LatLng p);
     }
 
     /**
      * Tolerance for determining if the value is 0. If the absolute value of a value is less than
      * this tolerance, it will be treated as 0.
+     * @hide
      */
     public static final double EPS = 1e-7;
 
-    /** The radius of earth. */
+    /**
+     * The radius of earth.
+     * @hide
+     */
     public static final int EARTH_RADIUS_METER = 6371 * 1000;
 
     private static final String TAG = "CbGeoUtils";
 
-    /** The TLV tags of WAC, defined in ATIS-0700041 5.2.3 WAC tag coding. */
+    // The TLV tags of WAC, defined in ATIS-0700041 5.2.3 WAC tag coding.
+    /** @hide */
     public static final int GEO_FENCING_MAXIMUM_WAIT_TIME = 0x01;
+    /** @hide */
     public static final int GEOMETRY_TYPE_POLYGON = 0x02;
+    /** @hide */
     public static final int GEOMETRY_TYPE_CIRCLE = 0x03;
 
-    /** The identifier of geometry in the encoded string. */
+    // The identifier of geometry in the encoded string.
+    /** @hide */
     private static final String CIRCLE_SYMBOL = "circle";
+    /** @hide */
     private static final String POLYGON_SYMBOL = "polygon";
 
     /** Point represent by (latitude, longitude). */
@@ -81,7 +99,8 @@
          * @param p the point use to calculate the subtraction result.
          * @return the result of this point subtract the given point {@code p}.
          */
-        public LatLng subtract(LatLng p) {
+        @NonNull
+        public LatLng subtract(@NonNull LatLng p) {
             return new LatLng(lat - p.lat, lng - p.lng);
         }
 
@@ -90,7 +109,7 @@
          * @param p the point use to calculate the distance.
          * @return the distance in meter.
          */
-        public double distance(LatLng p) {
+        public double distance(@NonNull LatLng p) {
             double dlat = Math.sin(0.5 * Math.toRadians(lat - p.lat));
             double dlng = Math.sin(0.5 * Math.toRadians(lng - p.lng));
             double x = dlat * dlat
@@ -106,6 +125,7 @@
 
     /**
      * The class represents a simple polygon with at least 3 points.
+     * @hide
      */
     public static class Polygon implements Geometry {
         /**
@@ -239,7 +259,10 @@
         }
     }
 
-    /** The class represents a circle. */
+    /**
+     * The class represents a circle.
+     * @hide
+     */
     public static class Circle implements Geometry {
         private final LatLng mCenter;
         private final double mRadiusMeter;
@@ -266,6 +289,7 @@
     /**
      * Parse the geometries from the encoded string {@code str}. The string must follow the
      * geometry encoding specified by {@link android.provider.Telephony.CellBroadcasts#GEOMETRIES}.
+     * @hide
      */
     @NonNull
     public static List<Geometry> parseGeometriesFromString(@NonNull String str) {
@@ -297,6 +321,7 @@
      *
      * @param geometries the list of geometry objects need to be encoded.
      * @return the encoded string.
+     * @hide
      */
     @NonNull
     public static String encodeGeometriesToString(List<Geometry> geometries) {
@@ -313,6 +338,7 @@
      * {@link android.provider.Telephony.CellBroadcasts#GEOMETRIES}.
      * @param geometry the geometry object need to be encoded.
      * @return the encoded string.
+     * @hide
      */
     @NonNull
     private static String encodeGeometryToString(@NonNull Geometry geometry) {
@@ -351,6 +377,7 @@
      *
      * @param str encoded lat/lng string.
      * @Return {@link LatLng} object.
+     * @hide
      */
     @NonNull
     public static LatLng parseLatLngFromString(@NonNull String str) {
@@ -361,6 +388,7 @@
     /**
      * @Return the sign of the given value {@code value} with the specified tolerance. Return 1
      * means the sign is positive, -1 means negative, 0 means the value will be treated as 0.
+     * @hide
      */
     public static int sign(double value) {
         if (value > EPS) return 1;
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 6df60ba..edc838c 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -62,6 +62,12 @@
     }
 
     /** @hide */
+    public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) {
+        this(cid.pci, cid.tac, cid.nrarfcn, cid.mcc, cid.mnc, cid.nci, cid.operatorNames.alphaLong,
+                cid.operatorNames.alphaShort);
+    }
+
+    /** @hide */
     public CellIdentityNr sanitizeLocationInfo() {
         return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
                 mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 18687d4..ae45307 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -374,6 +374,7 @@
             case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp);
             case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp);
             case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp);
+            case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp);
             default: return null;
         }
     }
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index cea8323..8b41b8b 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -45,6 +45,14 @@
         mCellSignalStrength = other.mCellSignalStrength;
     }
 
+    /** @hide */
+    public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr();
+        mCellIdentity = new CellIdentityNr(cil.cellidentity);
+        mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength);
+    }
+
     /**
      * @return a {@link CellIdentityNr} instance.
      */
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 85110c2..04ec4b6 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -354,6 +354,12 @@
      */
     public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
 
+    /**
+     * Indicates that an emergency call was placed, which caused the existing connection to be
+     * hung up.
+     */
+    public static final int OUTGOING_EMERGENCY_CALL_PLACED = 80;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Update toString() with the newly added disconnect type.
@@ -528,6 +534,8 @@
             return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
         case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
             return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
+        case OUTGOING_EMERGENCY_CALL_PLACED:
+            return "OUTGOING_EMERGENCY_CALL_PLACED";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index ef2f121..75a79d6 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -15,9 +15,11 @@
  */
 package android.telephony;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import java.util.Date;
 import android.util.Log;
 
 import java.security.KeyFactory;
@@ -25,18 +27,18 @@
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
 
 /**
  * Class to represent information sent by the carrier, which will be used to encrypt
  * the IMSI + IMPI. The ecryption is being done by WLAN, and the modem.
- *
  * @hide
  */
+@SystemApi
 public final class ImsiEncryptionInfo implements Parcelable {
 
     private static final String LOG_TAG = "ImsiEncryptionInfo";
 
-
     private final String mcc;
     private final String mnc;
     private final PublicKey publicKey;
@@ -45,11 +47,13 @@
     //Date-Time in UTC when the key will expire.
     private final Date expirationTime;
 
+    /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
                               byte[] key, Date expirationTime) {
         this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime);
     }
 
+    /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
                               PublicKey publicKey, Date expirationTime) {
         // todo need to validate that ImsiEncryptionInfo is being created with the correct params.
@@ -63,6 +67,7 @@
         this.expirationTime = expirationTime;
     }
 
+    /** @hide */
     public ImsiEncryptionInfo(Parcel in) {
         int length = in.readInt();
         byte b[] = new byte[length];
@@ -75,26 +80,40 @@
         expirationTime = new Date(in.readLong());
     }
 
+    /** @hide */
     public String getMnc() {
         return this.mnc;
     }
 
+    /** @hide */
     public String getMcc() {
         return this.mcc;
     }
 
+    /**
+     * Returns key identifier, a string that helps the authentication server to locate the
+     * private key to decrypt the permanent identity, or {@code null} when uavailable.
+     */
+    @Nullable
     public String getKeyIdentifier() {
         return this.keyIdentifier;
     }
 
+    /** @hide */
     public int getKeyType() {
         return this.keyType;
     }
 
+    /**
+     * Returns the carrier public key that is used for the IMSI encryption,
+     * or {@code null} when uavailable.
+     */
+    @Nullable
     public PublicKey getPublicKey() {
         return this.publicKey;
     }
 
+    /** @hide */
     public Date getExpirationTime() {
         return this.expirationTime;
     }
@@ -115,7 +134,7 @@
         return 0;
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
+    public static final @NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
             new Parcelable.Creator<ImsiEncryptionInfo>() {
                 @Override
                 public ImsiEncryptionInfo createFromParcel(Parcel in) {
@@ -129,7 +148,7 @@
             };
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         byte[] b = publicKey.getEncoded();
         dest.writeInt(b.length);
         dest.writeByteArray(b);
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index f929649..9f75332 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -23,6 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.PreciseCallStates;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseDisconnectCause;
 
@@ -48,22 +49,6 @@
 @SystemApi
 public final class PreciseCallState implements Parcelable {
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"PRECISE_CALL_STATE_"},
-            value = {
-                    PRECISE_CALL_STATE_NOT_VALID,
-                    PRECISE_CALL_STATE_IDLE,
-                    PRECISE_CALL_STATE_ACTIVE,
-                    PRECISE_CALL_STATE_HOLDING,
-                    PRECISE_CALL_STATE_DIALING,
-                    PRECISE_CALL_STATE_ALERTING,
-                    PRECISE_CALL_STATE_INCOMING,
-                    PRECISE_CALL_STATE_WAITING,
-                    PRECISE_CALL_STATE_DISCONNECTED,
-                    PRECISE_CALL_STATE_DISCONNECTING})
-    public @interface State {}
-
     /** Call state is not valid (Not received a call state). */
     public static final int PRECISE_CALL_STATE_NOT_VALID =      -1;
     /** Call state: No activity. */
@@ -85,9 +70,9 @@
     /** Call state: Disconnecting. */
     public static final int PRECISE_CALL_STATE_DISCONNECTING =  8;
 
-    private @State int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private @State int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private @State int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
     private int mDisconnectCause = DisconnectCause.NOT_VALID;
     private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
 
@@ -97,8 +82,9 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseCallState(@State int ringingCall, @State int foregroundCall,
-                            @State int backgroundCall, int disconnectCause,
+    public PreciseCallState(@PreciseCallStates int ringingCall,
+                            @PreciseCallStates int foregroundCall,
+                            @PreciseCallStates int backgroundCall, int disconnectCause,
                             int preciseDisconnectCause) {
         mRingingCallState = ringingCall;
         mForegroundCallState = foregroundCall;
@@ -131,21 +117,21 @@
     /**
      * Returns the precise ringing call state.
      */
-    public @State int getRingingCallState() {
+    public @PreciseCallStates int getRingingCallState() {
         return mRingingCallState;
     }
 
     /**
      * Returns the precise foreground call state.
      */
-    public @State int getForegroundCallState() {
+    public @PreciseCallStates int getForegroundCallState() {
         return mForegroundCallState;
     }
 
     /**
      * Returns the precise background call state.
      */
-    public @State int getBackgroundCallState() {
+    public @PreciseCallStates int getBackgroundCallState() {
         return mBackgroundCallState;
     }
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 3fd8990..1e601cf 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -30,6 +30,7 @@
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.NetworkRegistrationInfo.Domain;
 import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
@@ -155,32 +156,6 @@
      */
     public static final int DUPLEX_MODE_TDD = 2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" },
-            value = {
-                    RIL_RADIO_TECHNOLOGY_UNKNOWN,
-                    RIL_RADIO_TECHNOLOGY_GPRS,
-                    RIL_RADIO_TECHNOLOGY_EDGE,
-                    RIL_RADIO_TECHNOLOGY_UMTS,
-                    RIL_RADIO_TECHNOLOGY_IS95A,
-                    RIL_RADIO_TECHNOLOGY_IS95B,
-                    RIL_RADIO_TECHNOLOGY_1xRTT,
-                    RIL_RADIO_TECHNOLOGY_EVDO_0,
-                    RIL_RADIO_TECHNOLOGY_EVDO_A,
-                    RIL_RADIO_TECHNOLOGY_HSDPA,
-                    RIL_RADIO_TECHNOLOGY_HSUPA,
-                    RIL_RADIO_TECHNOLOGY_HSPA,
-                    RIL_RADIO_TECHNOLOGY_EVDO_B,
-                    RIL_RADIO_TECHNOLOGY_EHRPD,
-                    RIL_RADIO_TECHNOLOGY_LTE,
-                    RIL_RADIO_TECHNOLOGY_HSPAP,
-                    RIL_RADIO_TECHNOLOGY_GSM,
-                    RIL_RADIO_TECHNOLOGY_TD_SCDMA,
-                    RIL_RADIO_TECHNOLOGY_IWLAN,
-                    RIL_RADIO_TECHNOLOGY_LTE_CA,
-                    RIL_RADIO_TECHNOLOGY_NR})
-    public @interface RilRadioTechnology {}
     /**
      * Available radio technologies for GSM, UMTS and CDMA.
      * Duplicates the constants from hardware/radio/include/ril.h
diff --git a/telephony/java/android/telephony/SmsCbLocation.java b/telephony/java/android/telephony/SmsCbLocation.java
index adf7154..663e8e2 100644
--- a/telephony/java/android/telephony/SmsCbLocation.java
+++ b/telephony/java/android/telephony/SmsCbLocation.java
@@ -65,9 +65,12 @@
     /**
      * Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so
      * the same object can be reused for multiple broadcasts.
-     * @hide
+     *
+     * @param plmn the MCC/MNC of the network
+     * @param lac the GSM location area code, or UMTS service area code
+     * @param cid the GSM or UMTS cell ID
      */
-    public SmsCbLocation(String plmn, int lac, int cid) {
+    public SmsCbLocation(@NonNull String plmn, int lac, int cid) {
         mPlmn = plmn;
         mLac = lac;
         mCid = cid;
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index dc991b9..737ead1 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -25,9 +25,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Telephony.CellBroadcasts;
-
-import com.android.internal.telephony.CbGeoUtils;
-import com.android.internal.telephony.CbGeoUtils.Geometry;
+import android.telephony.CbGeoUtils.Geometry;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -140,8 +138,8 @@
     public @interface MessagePriority {}
 
     /**
-     * ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
-     * @hide
+     * Integer indicating that the maximum wait time is not set.
+     * Based on ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
      */
     public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255;
 
@@ -211,6 +209,7 @@
 
     /**
      * Create a new SmsCbMessage with the specified data.
+     * @hide
      */
     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
             @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
@@ -223,14 +222,14 @@
     }
 
     /**
-     * Create a new {@link SmsCbMessage} with the warning area coordinates information.
-     * @hide
+     * Create a new {@link SmsCbMessage} with the specified data, including warning area
+     * coordinates information.
      */
     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
-            SmsCbLocation location, int serviceCategory, String language, String body,
-            int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
-            int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis,
-            int slotIndex) {
+            @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
+            @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
+            @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec,
+            @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex) {
         mMessageFormat = messageFormat;
         mGeographicalScope = geographicalScope;
         mSerialNumber = serialNumber;
@@ -414,9 +413,8 @@
     /**
      * Get the Geo-Fencing Maximum Wait Time.
      * @return the time in second.
-     * @hide
      */
-    public int getMaximumWaitingTime() {
+    public int getMaximumWaitingDuration() {
         return mMaximumWaitTimeSec;
     }
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9d1b7a9..3c890a1 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -61,6 +61,7 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.telephony.ISetOpportunisticDataCallback;
 import com.android.internal.telephony.ISub;
@@ -76,6 +77,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
@@ -910,6 +912,11 @@
     private final Context mContext;
     private volatile INetworkPolicyManager mNetworkPolicy;
 
+    // Cache of Resource that has been created in getResourcesForSubId. Key is a Pair containing
+    // the Context and subId.
+    private static final Map<Pair<Context, Integer>, Resources> sResourcesCache =
+            new ConcurrentHashMap<>();
+
     /**
      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
      * <p>
@@ -2304,8 +2311,20 @@
      * @return Resources associated with Subscription.
      * @hide
      */
+    @NonNull
     public static Resources getResourcesForSubId(Context context, int subId,
             boolean useRootLocale) {
+        // Check if resources for this context and subId already exist in the resource cache.
+        // Resources that use the root locale are not cached.
+        Pair<Context, Integer> cacheKey = null;
+        if (isValidSubscriptionId(subId) && !useRootLocale) {
+            cacheKey = Pair.create(context, subId);
+            if (sResourcesCache.containsKey(cacheKey)) {
+                // Cache hit. Use cached Resources.
+                return sResourcesCache.get(cacheKey);
+            }
+        }
+
         final SubscriptionInfo subInfo =
                 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
 
@@ -2325,7 +2344,13 @@
         DisplayMetrics metrics = context.getResources().getDisplayMetrics();
         DisplayMetrics newMetrics = new DisplayMetrics();
         newMetrics.setTo(metrics);
-        return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+        Resources res = new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+
+        if (cacheKey != null) {
+            // Save the newly created Resources in the resource cache.
+            sResourcesCache.put(cacheKey, res);
+        }
+        return res;
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 55212cd..e99465d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -200,12 +200,29 @@
     /** @hide */
     static public final int OTASP_SIM_UNPROVISIONED = 5;
 
-    /** @hide */
+    /**
+     * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+     * available for use in ePDG links.
+     *
+     * @hide
+     */
+    @SystemApi
     static public final int KEY_TYPE_EPDG = 1;
 
-    /** @hide */
+    /**
+     * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+     * available for use in WLAN links.
+     *
+     * @hide
+     */
+    @SystemApi
     static public final int KEY_TYPE_WLAN = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"KEY_TYPE_"}, value = {KEY_TYPE_EPDG, KEY_TYPE_WLAN})
+    public @interface KeyType {}
+
     /**
      * No Single Radio Voice Call Continuity (SRVCC) handover is active.
      * See TS 23.216 for more information.
@@ -3814,25 +3831,27 @@
     }
 
     /**
-     * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
-     * This includes the public key and the key identifier. For multi-sim devices, if no subId
-     * has been specified, we will return the value for the dafault data sim.
-     * Return null if it is unavailable.
+     * Returns carrier specific information that will be used to encrypt the IMSI and IMPI,
+     * including the public key and the key identifier; or {@code null} if not available.
      * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * @param keyType whether the key is being used for wlan or epdg. Valid key types are
-     *        {@link TelephonyManager#KEY_TYPE_EPDG} or
-     *        {@link TelephonyManager#KEY_TYPE_WLAN}.
+     * For a multi-sim device, the dafault data sim is used if not specified.
+     * <p>
+     * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
+     *
+     * @param keyType whether the key is being used for EPDG or WLAN. Valid values are
+     *        {@link #KEY_TYPE_EPDG} or {@link #KEY_TYPE_WLAN}.
      * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
      *         IMSI and IMPI. This includes the public key and the key identifier. This information
-     *         will be stored in the device keystore. The system will return a null when no key was
-     *         found, and the carrier does not require a key. The system will throw
-     *         IllegalArgumentException when an invalid key is sent or when key is required but
+     *         will be stored in the device keystore. {@code null} will be returned when no key is
+     *         found, and the carrier does not require a key.
+     * @throws IllegalArgumentException when an invalid key is found or when key is required but
      *         not found.
      * @hide
      */
-    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
@@ -3860,14 +3879,21 @@
     }
 
     /**
-     * Resets the Carrier Keys in the database. This involves 2 steps:
+     * Resets the carrier keys used to encrypt the IMSI and IMPI.
+     * <p>
+     * This involves 2 steps:
      *  1. Delete the keys from the database.
      *  2. Send an intent to download new Certificates.
      * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * For a multi-sim device, the dafault data sim is used if not specified.
+     * <p>
+     * Requires Permission: MODIFY_PHONE_STATE.
+     *
+     * @see #getCarrierInfoForImsiEncryption
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
     public void resetCarrierKeysForImsiEncryption() {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -3894,7 +3920,7 @@
      * @return true if the digit at position keyType is 1, else false.
      * @hide
      */
-    private static boolean isKeyEnabled(int keyAvailability, int keyType) {
+    private static boolean isKeyEnabled(int keyAvailability, @KeyType int keyType) {
         int returnValue = (keyAvailability >> (keyType - 1)) & 1;
         return (returnValue == 1) ? true : false;
     }
@@ -3903,7 +3929,7 @@
      * If Carrier requires Imsi to be encrypted.
      * @hide
      */
-    private boolean isImsiEncryptionRequired(int subId, int keyType) {
+    private boolean isImsiEncryptionRequired(int subId, @KeyType int keyType) {
         CarrierConfigManager configManager =
                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) {
@@ -7673,8 +7699,8 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @SystemApi
-    public boolean isTetherApnRequired() {
-        return isTetherApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
+    public boolean isTetheringApnRequired() {
+        return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
     }
 
     /**
@@ -7684,11 +7710,11 @@
      * @return {@code true} if DUN APN is required for tethering.
      * @hide
      */
-    public boolean isTetherApnRequired(int subId) {
+    public boolean isTetheringApnRequired(int subId) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isTetherApnRequiredForSubscriber(subId);
+                return telephony.isTetheringApnRequiredForSubscriber(subId);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "hasMatchedTetherApnSetting RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -8806,7 +8832,10 @@
     @Deprecated
     public boolean isTtyModeSupported() {
         try {
-            TelecomManager telecomManager = TelecomManager.from(mContext);
+            TelecomManager telecomManager = null;
+            if (mContext != null) {
+                telecomManager = mContext.getSystemService(TelecomManager.class);
+            }
             if (telecomManager != null) {
                 return telecomManager.isTtySupported();
             }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index eb0e2f7..5fd0af5 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -979,25 +979,25 @@
 
     /**
      * Get the status of the MmTel Feature registered on this subscription.
+     * @param executor The executor that will be used to call the callback.
      * @param callback A callback containing an Integer describing the current state of the
      *                 MmTel feature, Which will be one of the following:
      *                 {@link ImsFeature#STATE_UNAVAILABLE},
      *                {@link ImsFeature#STATE_INITIALIZING},
      *                {@link ImsFeature#STATE_READY}. Will be called using the executor
      *                 specified when the service state has been retrieved from the IMS service.
-     * @param executor The executor that will be used to call the callback.
      * @throws ImsException if the IMS service associated with this subscription is not available or
      * the IMS service is not available.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void getFeatureState(@NonNull @ImsFeature.ImsState Consumer<Integer> callback,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException {
-        if (callback == null) {
-            throw new IllegalArgumentException("Must include a non-null Consumer.");
-        }
+    public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must include a non-null Consumer.");
+        }
         try {
             getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
                 @Override
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 119f890..e96d082 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -199,12 +199,19 @@
         /** @hide*/
         @Retention(RetentionPolicy.SOURCE)
         @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+                CAPABILITY_TYPE_NONE,
                 CAPABILITY_TYPE_OPTIONS_UCE,
                 CAPABILITY_TYPE_PRESENCE_UCE
         })
         public @interface RcsImsCapabilityFlag {}
 
         /**
+         * Undefined capability type for initialization
+         * @hide
+         */
+        public static final int CAPABILITY_TYPE_NONE = 0;
+
+        /**
          * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
          * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
          * If not set, this RcsFeature should not service capability requests.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b502ee7..2f18049e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -819,7 +819,7 @@
      * @return {@code true} if DUN APN is required for tethering.
      * @hide
      */
-    boolean isTetherApnRequiredForSubscriber(int subId);
+    boolean isTetheringApnRequiredForSubscriber(int subId);
 
     /**
     * Enables framework IMS and triggers IMS Registration.
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index d29ef35..d36d95b 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -20,7 +20,6 @@
 import android.os.Build;
 import android.provider.Telephony;
 import android.telephony.SmsMessage;
-import android.text.Emoji;
 
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 
@@ -404,9 +403,9 @@
             if (!breakIterator.isBoundary(nextPos)) {
                 int breakPos = breakIterator.preceding(nextPos);
                 while (breakPos + 4 <= nextPos
-                        && Emoji.isRegionalIndicatorSymbol(
+                        && isRegionalIndicatorSymbol(
                             Character.codePointAt(msgBody, breakPos))
-                        && Emoji.isRegionalIndicatorSymbol(
+                        && isRegionalIndicatorSymbol(
                             Character.codePointAt(msgBody, breakPos + 2))) {
                     // skip forward over flags (pairs of Regional Indicator Symbol)
                     breakPos += 4;
@@ -422,6 +421,11 @@
         return nextPos;
     }
 
+    private static boolean isRegionalIndicatorSymbol(int codePoint) {
+        /** Based on http://unicode.org/Public/emoji/3.0/emoji-sequences.txt */
+        return 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF;
+    }
+
     /**
      * Calculate the TextEncodingDetails of a message encoded in Unicode.
      */
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index c3d490a..5766287 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -25,17 +25,17 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
+import android.telephony.CbGeoUtils;
+import android.telephony.CbGeoUtils.Circle;
+import android.telephony.CbGeoUtils.Geometry;
+import android.telephony.CbGeoUtils.LatLng;
+import android.telephony.CbGeoUtils.Polygon;
 import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
 import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.R;
-import com.android.internal.telephony.CbGeoUtils;
-import com.android.internal.telephony.CbGeoUtils.Circle;
-import com.android.internal.telephony.CbGeoUtils.Geometry;
-import com.android.internal.telephony.CbGeoUtils.LatLng;
-import com.android.internal.telephony.CbGeoUtils.Polygon;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.gsm.GsmSmsCbMessage.GeoFencingTriggerMessage.CellBroadcastIdentity;
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 727684e..1de6260 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -765,6 +765,12 @@
 
     /** {@hide} */
     @Override
+    public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    @Override
     public int getUserId() {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
new file mode 100644
index 0000000..5e9ef8e
--- /dev/null
+++ b/tests/PlatformCompatGating/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+    name: "PlatformCompatGating",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    certificate: "platform",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "junit",
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+        "platform-compat-test-rules"
+    ],
+}
diff --git a/tests/PlatformCompatGating/AndroidManifest.xml b/tests/PlatformCompatGating/AndroidManifest.xml
new file mode 100644
index 0000000..7f14b83
--- /dev/null
+++ b/tests/PlatformCompatGating/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.gating">
+    <application android:label="GatingTest">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.tests.gating"/>
+</manifest>
diff --git a/tests/PlatformCompatGating/AndroidTest.xml b/tests/PlatformCompatGating/AndroidTest.xml
new file mode 100644
index 0000000..c626848
--- /dev/null
+++ b/tests/PlatformCompatGating/AndroidTest.xml
@@ -0,0 +1,30 @@
+<!-- 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="Test compatibility change gating.">
+    <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="PlatformCompatGating.apk"/>
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="Gating"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.tests.gating"/>
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
new file mode 100644
index 0000000..731be8e
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/compat/testing/DummyApi.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compat.testing;
+
+import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * This is a dummy API to test gating
+ *
+ * @hide
+ */
+public class DummyApi {
+
+    public static final long CHANGE_ID = 666013;
+    public static final long CHANGE_ID_1 = 666014;
+    public static final long CHANGE_ID_2 = 666015;
+    public static final long CHANGE_SYSTEM_SERVER = 666016;
+
+    /**
+     * Dummy method
+     * @return "A" if change is enabled, "B" otherwise.
+     */
+    public static String dummyFunc() {
+        if (Compatibility.isChangeEnabled(CHANGE_ID)) {
+            return "A";
+        }
+        return "B";
+    }
+
+    /**
+     * Dummy combined method
+     * @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled,
+               "1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled,
+               "2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled,
+               "3" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is enabled.
+     */
+    public static String dummyCombinedFunc() {
+        if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "0";
+        } else if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "1";
+        } else if (Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "2";
+        }
+        return "3";
+    }
+
+    /**
+     * Dummy api using system server API.
+     */
+    public static boolean dummySystemServer(Context context) {
+        IPlatformCompat platformCompat = IPlatformCompat.Stub
+                .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+        if (platformCompat == null) {
+            throw new RuntimeException("Could not obtain IPlatformCompat instance!");
+        }
+        String packageName = context.getPackageName();
+        try {
+            return platformCompat.isChangeEnabledByPackageName(CHANGE_SYSTEM_SERVER, packageName,
+                                                            context.getUserId());
+        } catch (RemoteException e) {
+            throw new RuntimeException("Could not get change value!", e);
+        }
+    }
+}
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
new file mode 100644
index 0000000..dc317f19
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatGatingTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+package com.android.tests.gating;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compat.testing.DummyApi;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for platform compatibility change gating.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PlatformCompatGatingTest {
+
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingPositive() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("A");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingNegative() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("B");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined0() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("0");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1})
+    @EnableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined1() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("1");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1})
+    @DisableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined2() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("2");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined3() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("3");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+    public void testDummyGatingPositiveSystemServer() {
+        assertThat(
+                DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isTrue();
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+    public void testDummyGatingNegativeSystemServer() {
+        assertThat(
+                DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isFalse();
+    }
+}
diff --git a/tests/PlatformCompatGating/test-rules/Android.bp b/tests/PlatformCompatGating/test-rules/Android.bp
new file mode 100644
index 0000000..8211ef5
--- /dev/null
+++ b/tests/PlatformCompatGating/test-rules/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_library {
+    name: "platform-compat-test-rules",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "junit",
+        "android-support-test",
+        "truth-prebuilt",
+        "core-compat-test-rules"
+    ],
+}
\ No newline at end of file
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
new file mode 100644
index 0000000..932ec64
--- /dev/null
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.compat.testing;
+
+import android.app.Instrumentation;
+import android.compat.Compatibility;
+import android.compat.Compatibility.ChangeConfig;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.IPlatformCompat;
+
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
+import org.junit.runners.model.Statement;
+
+/**
+ * Allows tests to specify the which change to disable.
+ *
+ * <p>To use add the following to the test class. It will only change the behavior of a test method
+ * if it is annotated with
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges}.
+ * </p>
+ * <pre>
+ * @Rule
+ * public TestRule compatChangeRule = new PlatformCompatChangeRule();
+ * </pre>
+ *
+ * <p>Each test method that needs to disable a specific change needs to be annotated
+ * with {@link libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges} and/or
+ * {@link libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges} specifying the change
+ * id. e.g.:
+ * </p>
+ * <pre>
+ *   @Test
+ *   @DisableCompatChanges({42})
+ *   public void testAsIfChange42Disabled() {
+ *     // check behavior
+ *   }
+ *
+ *   @Test
+ *   @EnableCompatChanges({42})
+ *   public void testAsIfChange42Enabled() {
+ *     // check behavior
+ *
+ * </pre>
+ */
+public class PlatformCompatChangeRule extends CoreCompatChangeRule {
+
+    @Override
+    protected Statement createStatementForConfig(final Statement statement, ChangeConfig config) {
+        return new CompatChangeStatement(statement, config);
+    }
+
+
+    private static class CompatChangeStatement extends Statement {
+        private final Statement mTestStatement;
+        private final ChangeConfig mConfig;
+
+        private CompatChangeStatement(Statement testStatement, ChangeConfig config) {
+            this.mTestStatement = testStatement;
+            this.mConfig = config;
+        }
+
+        @Override
+        public void evaluate() throws Throwable {
+            Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+            String packageName = instrumentation.getTargetContext().getPackageName();
+            IPlatformCompat platformCompat = IPlatformCompat.Stub
+                    .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+            if (platformCompat == null) {
+                throw new IllegalStateException("Could not get IPlatformCompat service!");
+            }
+            Compatibility.setOverrides(mConfig);
+            try {
+                platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
+                        packageName);
+                try {
+                    mTestStatement.evaluate();
+                } finally {
+                    platformCompat.clearOverridesForTest(packageName);
+                }
+            } catch (RemoteException e) {
+                throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
+            } finally {
+                Compatibility.clearOverrides();
+            }
+        }
+    }
+}
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index aec4055..231d045b 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -12,88 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-android_test_helper_app {
-    name: "RollbackTestAppAv1",
-    manifest: "TestApp/Av1.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v1"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppAv2",
-    manifest: "TestApp/Av2.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppAv3",
-    manifest: "TestApp/Av3.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v3"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppACrashingV2",
-    manifest: "TestApp/ACrashingV2.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppBv1",
-    manifest: "TestApp/Bv1.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v1"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppBv2",
-    manifest: "TestApp/Bv2.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v2"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppASplitV1",
-    manifest: "TestApp/Av1.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v1"],
-    package_splits: ["anydpi"],
-}
-
-android_test_helper_app {
-    name: "RollbackTestAppASplitV2",
-    manifest: "TestApp/Av2.xml",
-    sdk_version: "current",
-    srcs: ["TestApp/src/**/*.java"],
-    resource_dirs: ["TestApp/res_v2"],
-    package_splits: ["anydpi"],
-}
-
 android_test {
     name: "RollbackTest",
     manifest: "RollbackTest/AndroidManifest.xml",
     srcs: ["RollbackTest/src/**/*.java"],
-    static_libs: ["androidx.test.rules"],
+    static_libs: ["androidx.test.rules", "cts-rollback-lib", "cts-install-lib"],
     test_suites: ["general-tests"],
-    java_resources: [
-        ":RollbackTestAppAv1",
-        ":RollbackTestAppAv2",
-        ":RollbackTestAppAv3",
-        ":RollbackTestAppACrashingV2",
-        ":RollbackTestAppBv1",
-        ":RollbackTestAppBv2",
-        ":RollbackTestAppASplitV1",
-        ":RollbackTestAppASplitV2",
-    ],
     test_config: "RollbackTest.xml",
     // TODO: sdk_version: "test_current" when Intent#resolveSystemservice is TestApi
 }
@@ -105,3 +29,11 @@
     test_suites: ["general-tests"],
     test_config: "StagedRollbackTest.xml",
 }
+
+java_test_host {
+    name: "MultiUserRollbackTest",
+    srcs: ["MultiUserRollbackTest/src/**/*.java"],
+    libs: ["tradefed"],
+    test_suites: ["general-tests"],
+    test_config: "MultiUserRollbackTest.xml",
+}
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
new file mode 100644
index 0000000..41cec46
--- /dev/null
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs rollback tests for multiple users">
+    <option name="test-suite-tag" value="MultiUserRollbackTest" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
+    </test>
+</configuration>
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
new file mode 100644
index 0000000..52f6eba
--- /dev/null
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback.host;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Runs rollback tests for multiple users.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class MultiUserRollbackTest extends BaseHostJUnit4Test {
+    // The user that was running originally when the test starts.
+    private int mOriginalUserId;
+    private int mSecondaryUserId = -1;
+    private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
+    private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
+
+
+    @After
+    public void tearDown() throws Exception {
+        getDevice().switchUser(mOriginalUserId);
+        getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
+        removeSecondaryUserIfNecessary();
+    }
+
+    @Before
+    public void setup() throws Exception {
+        mOriginalUserId = getDevice().getCurrentUser();
+        installPackageAsUser("RollbackTest.apk", true, mOriginalUserId);
+        createAndSwitchToSecondaryUserIfNecessary();
+        installPackageAsUser("RollbackTest.apk", true, mSecondaryUserId);
+    }
+
+    @Test
+    public void testBasicForSecondaryUser() throws Exception {
+        runPhaseForUsers("testBasic", mSecondaryUserId);
+    }
+
+    @Test
+    public void testMultipleUsers() throws Exception {
+        runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
+        runPhaseForUsers("testMultipleUsersUpgradeToV2", mOriginalUserId);
+        runPhaseForUsers("testMultipleUsersUpdateUserData", mOriginalUserId, mSecondaryUserId);
+        switchToUser(mOriginalUserId);
+        getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
+        runPhaseForUsers("testMultipleUsersVerifyUserdataRollback", mOriginalUserId,
+                mSecondaryUserId);
+    }
+
+    /**
+     * Run the phase for the given user ids, in the order they are given.
+     */
+    private void runPhaseForUsers(String phase, int... userIds) throws Exception {
+        for (int userId: userIds) {
+            switchToUser(userId);
+            assertTrue(runDeviceTests("com.android.tests.rollback",
+                    "com.android.tests.rollback.MultiUserRollbackTest",
+                    phase));
+        }
+    }
+
+    private void removeSecondaryUserIfNecessary() throws Exception {
+        if (mSecondaryUserId != -1) {
+            getDevice().removeUser(mSecondaryUserId);
+            mSecondaryUserId = -1;
+        }
+    }
+
+    private void createAndSwitchToSecondaryUserIfNecessary() throws Exception {
+        if (mSecondaryUserId == -1) {
+            mOriginalUserId = getDevice().getCurrentUser();
+            mSecondaryUserId = getDevice().createUser("MultiUserRollbackTest_User"
+                    + System.currentTimeMillis());
+            switchToUser(mSecondaryUserId);
+        }
+    }
+
+    private void switchToUser(int userId) throws Exception {
+        if (getDevice().getCurrentUser() == userId) {
+            return;
+        }
+
+        assertTrue(getDevice().switchUser(userId));
+        for (int i = 0; i < SWITCH_USER_COMPLETED_NUMBER_OF_POLLS; ++i) {
+            String userState = getDevice().executeShellCommand("am get-started-user-state "
+                    + userId);
+            if (userState.contains("RUNNING_UNLOCKED")) {
+                return;
+            }
+            Thread.sleep(SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS);
+        }
+        fail("User switch to user " + userId + " timed out");
+    }
+}
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 70cd867..a14b01c 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -22,8 +22,9 @@
         <option name="package" value="com.android.tests.rollback" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
 
-        <!-- Exclude the StagedRollbackTest tests, which needs to be specially
-             driven from the StagedRollbackTest host test -->
+        <!-- Exclude the StagedRollbackTest and MultiUserRollbackTest tests, which need to be
+             specially driven from the StagedRollbackTest and MultiUserRollbackTest host test -->
         <option name="exclude-filter" value="com.android.tests.rollback.StagedRollbackTest" />
+        <option name="exclude-filter" value="com.android.tests.rollback.MultiUserRollbackTest" />
     </test>
 </configuration>
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 5380dc9..2b8c964 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.android.tests.rollback" >
 
     <application>
-        <receiver android:name="com.android.tests.rollback.LocalIntentSender"
+        <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
deleted file mode 100644
index 267ef73..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.tests.rollback;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * Make IntentSender that sends intent locally.
- */
-public class LocalIntentSender extends BroadcastReceiver {
-
-    private static final String TAG = "RollbackTest";
-
-    private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        sIntentSenderResults.add(intent);
-    }
-
-    /**
-     * Get a LocalIntentSender.
-     */
-    static IntentSender getIntentSender() {
-        Context context = InstrumentationRegistry.getContext();
-        Intent intent = new Intent(context, LocalIntentSender.class);
-        PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
-        return pending.getIntentSender();
-    }
-
-    /**
-     * Returns the most recent Intent sent by a LocalIntentSender.
-     */
-    static Intent getIntentSenderResult() throws InterruptedException {
-        return sIntentSenderResults.take();
-    }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
new file mode 100644
index 0000000..0ffe041
--- /dev/null
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+@RunWith(JUnit4.class)
+public class MultiUserRollbackTest {
+
+    @Before
+    public void adoptShellPermissions() {
+        InstallUtils.adoptShellPermissionIdentity(
+                Manifest.permission.INSTALL_PACKAGES,
+                Manifest.permission.DELETE_PACKAGES,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
+                Manifest.permission.MANAGE_ROLLBACKS);
+    }
+
+    @After
+    public void dropShellPermissions() {
+        InstallUtils.dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testBasic() throws Exception {
+        new RollbackTest().testBasic();
+    }
+
+    /**
+     * Install version 1 of the test app. This method is run for both users.
+     */
+    @Test
+    public void testMultipleUsersInstallV1() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+        Install.single(TestApp.A1).commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+    }
+
+    /**
+     * Upgrade the test app to version 2. This method should only run once as the system user,
+     * and will update the app for both users.
+     */
+    @Test
+    public void testMultipleUsersUpgradeToV2() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        Install.single(TestApp.A2).setEnableRollback().commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TestApp.A);
+        assertThat(rollback).isNotNull();
+        assertThat(rollback).packagesContainsExactly(
+                Rollback.from(TestApp.A2).to(TestApp.A1));
+    }
+
+    /**
+     * This method is run for both users. Assert that the test app has upgraded for both users, and
+     * update their userdata to reflect this new version.
+     */
+    @Test
+    public void testMultipleUsersUpdateUserData() {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.processUserData(TestApp.A);
+    }
+
+    /**
+     * The system will have rolled back the test app at this stage. Verify that the rollback has
+     * taken place, and that the userdata has been correctly rolled back. This method is run for
+     * both users.
+     */
+    @Test
+    public void testMultipleUsersVerifyUserdataRollback() {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+    }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
deleted file mode 100644
index ebe5418..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.tests.rollback;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A broadcast receiver that can be used to get
- * ACTION_ROLLBACK_COMMITTED broadcasts.
- */
-class RollbackBroadcastReceiver extends BroadcastReceiver {
-
-    private static final String TAG = "RollbackTest";
-
-    private final BlockingQueue<Intent> mRollbackBroadcasts = new LinkedBlockingQueue<>();
-
-    /**
-     * Creates a RollbackBroadcastReceiver and registers it with the given
-     * context.
-     */
-    RollbackBroadcastReceiver() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
-        InstrumentationRegistry.getContext().registerReceiver(this, filter);
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        Log.i(TAG, "Received rollback broadcast intent");
-        mRollbackBroadcasts.add(intent);
-    }
-
-    /**
-     * Polls for at most the given amount of time for the next rollback
-     * broadcast.
-     */
-    Intent poll(long timeout, TimeUnit unit) throws InterruptedException {
-        return mRollbackBroadcasts.poll(timeout, unit);
-    }
-
-    /**
-     * Waits forever for the next rollback broadcast.
-     */
-    Intent take() throws InterruptedException {
-        return mRollbackBroadcasts.take();
-    }
-
-    /**
-     * Unregisters this broadcast receiver.
-     */
-    void unregister() {
-        InstrumentationRegistry.getContext().unregisterReceiver(this);
-    }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 1b002ca..277c04f 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,14 +16,14 @@
 
 package com.android.tests.rollback;
 
-import static com.android.tests.rollback.RollbackTestUtils.assertPackageRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
-import static com.android.tests.rollback.RollbackTestUtils.processUserData;
+import static com.android.cts.install.lib.InstallUtils.processUserData;
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForAvailableRollback;
+import static com.android.cts.rollback.lib.RollbackUtils.waitForUnavailableRollback;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.fail;
 
 import android.Manifest;
@@ -31,15 +31,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.VersionedPackage;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.provider.DeviceConfig;
-import android.provider.Settings;
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackBroadcastReceiver;
+import com.android.cts.rollback.lib.RollbackUtils;
+
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,8 +63,6 @@
 
     private static final String TAG = "RollbackTest";
 
-    private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
-    private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
     private static final String INSTRUMENTED_APP = "com.android.tests.rollback";
 
     // copied from PackageManagerService#PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS
@@ -88,7 +92,7 @@
         context.registerReceiver(enableRollbackReceiver, enableRollbackFilter);
 
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -97,18 +101,18 @@
             // Register a broadcast receiver for notification when the
             // rollback has been committed.
             RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            // Uninstall TEST_APP_A
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // Uninstall TestApp.A
+            Uninstall.packages(TestApp.A);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
             // TODO: There is currently a race condition between when the app is
             // uninstalled and when rollback manager deletes the rollback. Fix it
             // so that's not the case!
             for (int i = 0; i < 5; ++i) {
                 RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                        rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+                        rm.getRecentlyCommittedRollbacks(), TestApp.A);
                 if (rollback != null) {
                     Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
                     Thread.sleep(1000);
@@ -116,50 +120,55 @@
             }
 
             // The app should not be available for rollback.
-            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+            waitForUnavailableRollback(TestApp.A);
 
             // There should be no recently committed rollbacks for this package.
-            assertNull(getUniqueRollbackInfoForPackage(
-                        rm.getRecentlyCommittedRollbacks(), TEST_APP_A));
+            assertThat(getUniqueRollbackInfoForPackage(
+                        rm.getRecentlyCommittedRollbacks(), TestApp.A)).isNull();
 
             // Install v1 of the app (without rollbacks enabled).
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Install.single(TestApp.A1).commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
             // Upgrade from v1 to v2, with rollbacks enabled.
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+            RollbackInfo available = waitForAvailableRollback(TestApp.A);
+            assertThat(available).isNotStaged();
+            assertThat(available).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
             // We should not have received any rollback requests yet.
             // TODO: Possibly flaky if, by chance, some other app on device
             // happens to be rolled back at the same time?
-            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+            assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
 
             // Roll back the app.
-            RollbackTestUtils.rollback(rollback.getRollbackId());
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            RollbackUtils.rollback(available.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
             // Verify we received a broadcast for the rollback.
             // TODO: Race condition between the timeout and when the broadcast is
             // received could lead to test flakiness.
             Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
-            assertNotNull(broadcast);
-            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+            assertThat(broadcast).isNotNull();
+            assertThat(broadcastReceiver.poll(0, TimeUnit.SECONDS)).isNull();
 
             // Verify the recent rollback has been recorded.
-            rollback = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+            RollbackInfo committed = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(committed).isNotNull();
+            assertThat(committed).isNotStaged();
+            assertThat(committed).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
+            assertThat(committed).hasRollbackId(available.getRollbackId());
 
             broadcastReceiver.unregister();
             context.unregisterReceiver(enableRollbackReceiver);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -169,50 +178,54 @@
     @Test
     public void testAvailableRollbackPersistence() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Uninstall.packages(TestApp.B);
+            Install.single(TestApp.B1).commit();
+            Install.single(TestApp.B2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // Both test apps should now be available for rollback.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+            assertThat(rollbackA).isNotNull();
+            assertThat(rollbackA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+            assertThat(rollbackB).isNotNull();
+            assertThat(rollbackB).packagesContainsExactly(
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+            rollbackA = waitForAvailableRollback(TestApp.A);
+            assertThat(rollbackA).isNotNull();
+            assertThat(rollbackA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+            rollbackB = waitForAvailableRollback(TestApp.B);
+            assertThat(rollbackB).isNotNull();
+            assertThat(rollbackB).packagesContainsExactly(
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Rollback of B should not rollback A
-            RollbackTestUtils.rollback(rollbackB.getRollbackId());
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            RollbackUtils.rollback(rollbackB.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -222,49 +235,76 @@
     @Test
     public void testAvailableMultiPackageRollbackPersistence() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.installMultiPackage(false,
-                    "RollbackTestAppAv1.apk",
-                    "RollbackTestAppBv1.apk");
-            RollbackTestUtils.installMultiPackage(true,
-                    "RollbackTestAppAv2.apk",
-                    "RollbackTestAppBv2.apk");
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Uninstall.packages(TestApp.A, TestApp.B);
+            Install.multi(TestApp.A1, TestApp.B1).commit();
+            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
+
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoForAandB(rollbackA);
+            RollbackInfo availableA = waitForAvailableRollback(TestApp.A);
+            assertThat(availableA).isNotNull();
+            assertThat(availableA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoForAandB(rollbackB);
+            RollbackInfo availableB = waitForAvailableRollback(TestApp.B);
+            assertThat(availableB).isNotNull();
+            assertThat(availableB).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
+
+            // Assert they're both the same rollback
+            assertThat(availableA).hasRollbackId(availableB.getRollbackId());
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // The apps should still be available for rollback.
-            rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoForAandB(rollbackA);
+            availableA = waitForAvailableRollback(TestApp.A);
+            assertThat(availableA).isNotNull();
+            assertThat(availableA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
-            rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoForAandB(rollbackB);
+            availableB = waitForAvailableRollback(TestApp.B);
+            assertThat(availableB).isNotNull();
+            assertThat(availableB).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Rollback of B should rollback A as well
-            RollbackTestUtils.rollback(rollbackB.getRollbackId());
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            RollbackUtils.rollback(availableB.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
+
+            RollbackInfo committedA = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(committedA).isNotNull();
+            assertThat(committedA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
+
+            RollbackInfo committedB = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(committedB).isNotNull();
+            assertThat(committedB).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
+
+            // Assert they're both the same rollback
+            assertThat(committedA).hasRollbackId(committedB.getRollbackId());
+            assertThat(committedA).hasRollbackId(availableA.getRollbackId());
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -274,42 +314,49 @@
     @Test
     public void testRecentlyCommittedRollbackPersistence() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
+            RollbackInfo available = waitForAvailableRollback(TestApp.A);
+            assertThat(available).isNotNull();
 
             // Roll back the app.
-            VersionedPackage cause = new VersionedPackage(
-                    "com.android.tests.rollback.testapp.Foo", 42);
-            RollbackTestUtils.rollback(rollback.getRollbackId(), cause);
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            TestApp cause = new TestApp("Foo", "com.android.tests.rollback.testapp.Foo",
+                    /*versionCode*/ 42, /*isApex*/ false);
+            RollbackUtils.rollback(available.getRollbackId(), cause);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
             // Verify the recent rollback has been recorded.
-            rollback = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause);
+            RollbackInfo committed = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(committed).isNotNull();
+            assertThat(committed).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
+            assertThat(committed).causePackagesContainsExactly(cause);
 
             // Reload the persisted data.
             rm.reloadPersistedData();
 
             // Verify the recent rollback is still recorded.
-            rollback = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, cause);
+            committed = getUniqueRollbackInfoForPackage(
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(committed).isNotNull();
+            assertThat(committed).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
+            assertThat(committed).causePackagesContainsExactly(cause);
+            assertThat(committed).hasRollbackId(available.getRollbackId());
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -320,10 +367,10 @@
     public void testRollbackExpiresAfterLifetime() throws Exception {
         long expirationTime = TimeUnit.SECONDS.toMillis(30);
         long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
 
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -336,39 +383,43 @@
             // Pull the new expiration time from DeviceConfig
             rm.reloadPersistedData();
 
-            // Uninstall TEST_APP_A
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // Uninstall TestApp.A
+            Uninstall.packages(TestApp.A);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
             // Install v1 of the app (without rollbacks enabled).
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Install.single(TestApp.A1).commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
             // Upgrade from v1 to v2, with rollbacks enabled.
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // Check that the rollback data has not expired
             Thread.sleep(1000);
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            // Give it a little more time, but still not the long enough to expire
+            // Give it a little more time, but still not long enough to expire
             Thread.sleep(expirationTime / 2);
             rollback = getUniqueRollbackInfoForPackage(
-                rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+                    rm.getAvailableRollbacks(), TestApp.A);
+            assertThat(rollback).isNotNull();
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
             // Check that the data has expired after the expiration time (with a buffer of 1 second)
             Thread.sleep(expirationTime / 2);
-            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+            rollback = getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TestApp.A);
+            assertThat(rollback).isNull();
 
         } finally {
             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
                     RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -380,10 +431,10 @@
     public void testTimeChangeDoesNotAffectLifetime() throws Exception {
         long expirationTime = TimeUnit.SECONDS.toMillis(30);
         long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
 
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -398,24 +449,25 @@
             rm.reloadPersistedData();
 
             // Install app A with rollback enabled
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             Thread.sleep(expirationTime / 2);
 
             // Install app B with rollback enabled
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Uninstall.packages(TestApp.B);
+            Install.single(TestApp.B1).commit();
+            Install.single(TestApp.B2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
+
             // 1 second buffer
             Thread.sleep(1000);
 
             try {
                 // Change the time
-                RollbackTestUtils.forwardTimeBy(expirationTime);
+                RollbackUtils.forwardTimeBy(expirationTime);
 
                 // 1 second buffer to allow Rollback Manager to handle time change before loading
                 // persisted data
@@ -427,24 +479,31 @@
                 // Wait until rollback for app A has expired
                 // This will trigger an expiration run that should expire app A but not B
                 Thread.sleep(expirationTime / 2);
-                assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+                RollbackInfo rollback =
+                        getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A);
+                assertThat(rollback).isNull();
 
                 // Rollback for app B should not be expired
-                RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                        rm.getAvailableRollbacks(), TEST_APP_B);
-                assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollback);
+                rollback = getUniqueRollbackInfoForPackage(
+                        rm.getAvailableRollbacks(), TestApp.B);
+                assertThat(rollback).isNotNull();
+                assertThat(rollback).packagesContainsExactly(
+                        Rollback.from(TestApp.B2).to(TestApp.B1));
 
                 // Wait until rollback for app B has expired
                 Thread.sleep(expirationTime / 2);
-                assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B));
+                rollback = getUniqueRollbackInfoForPackage(
+                        rm.getAvailableRollbacks(), TestApp.B);
+                // Rollback should be expired by now
+                assertThat(rollback).isNull();
             } finally {
-                RollbackTestUtils.forwardTimeBy(-expirationTime);
+                RollbackUtils.forwardTimeBy(-expirationTime);
             }
         } finally {
             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
                     RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -455,30 +514,30 @@
     @Test
     public void testRollbackExpiration() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            RollbackManager rm = RollbackUtils.getRollbackManager();
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             // The app should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
             // Expire the rollback.
-            rm.expireRollbackForPackage(TEST_APP_A);
+            rm.expireRollbackForPackage(TestApp.A);
 
             // The rollback should no longer be available.
-            assertNull(getUniqueRollbackInfoForPackage(
-                        rm.getAvailableRollbacks(), TEST_APP_A));
+            assertThat(getUniqueRollbackInfoForPackage(
+                        rm.getAvailableRollbacks(), TestApp.A)).isNull();
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -488,24 +547,22 @@
     @Test
     public void testUserDataRollback() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            processUserData(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            processUserData(TEST_APP_A);
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            processUserData(TestApp.A);
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            processUserData(TestApp.A);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            RollbackTestUtils.rollback(rollback.getRollbackId());
-            processUserData(TEST_APP_A);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            RollbackUtils.rollback(rollback.getRollbackId());
+            processUserData(TestApp.A);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -515,30 +572,23 @@
     @Test
     public void testRollbackWithSplits() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.installSplit(false,
-                    "RollbackTestAppASplitV1.apk",
-                    "RollbackTestAppASplitV1_anydpi.apk");
-            processUserData(TEST_APP_A);
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.ASplit1).commit();
+            processUserData(TestApp.A);
 
-            RollbackTestUtils.installSplit(true,
-                    "RollbackTestAppASplitV2.apk",
-                    "RollbackTestAppASplitV2_anydpi.apk");
-            processUserData(TEST_APP_A);
+            Install.single(TestApp.ASplit2).setEnableRollback().commit();
+            processUserData(TestApp.A);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertNotNull(rollback);
-            RollbackTestUtils.rollback(rollback.getRollbackId());
-            processUserData(TEST_APP_A);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            RollbackUtils.rollback(rollback.getRollbackId());
+            processUserData(TestApp.A);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -559,7 +609,7 @@
 
         // Confirm that we really haven't received the broadcast.
         // TODO: How long to wait for the expected timeout?
-        assertNull(broadcastReceiver.poll(5, TimeUnit.SECONDS));
+        assertThat(broadcastReceiver.poll(5, TimeUnit.SECONDS)).isNull();
 
         // TODO: Do we need to do this? Do we need to ensure this is always
         // called, even when the test fails?
@@ -573,48 +623,47 @@
     @Test
     public void testMultipleRollbackAvailable() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Uninstall.packages(TestApp.B);
+            Install.single(TestApp.B1).commit();
+            Install.single(TestApp.B2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // Both test apps should now be available for rollback, and the
             // RollbackInfo returned for the rollbacks should be correct.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+            assertThat(rollbackA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+            assertThat(rollbackB).packagesContainsExactly(
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Executing rollback should roll back the correct package.
-            RollbackTestUtils.rollback(rollbackA.getRollbackId());
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            RollbackUtils.rollback(rollbackA.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackTestUtils.rollback(rollbackB.getRollbackId());
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            RollbackUtils.rollback(rollbackB.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -626,7 +675,7 @@
     public void testManageRollbacksPermission() throws Exception {
         // We shouldn't be allowed to call any of the RollbackManager APIs
         // without the MANAGE_ROLLBACKS permission.
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
 
         try {
             rm.getAvailableRollbacks();
@@ -659,7 +708,7 @@
         }
 
         try {
-            rm.expireRollbackForPackage(TEST_APP_A);
+            rm.expireRollbackForPackage(TestApp.A);
             fail("expected SecurityException");
         } catch (SecurityException e) {
             // Expected.
@@ -673,26 +722,27 @@
     @Test
     public void testEnableRollbackPermission() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES);
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+            Install.single(TestApp.A2).setEnableRollback().commit();
 
             // We expect v2 of the app was installed, but rollback has not
             // been enabled.
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+            RollbackManager rm = RollbackUtils.getRollbackManager();
+            assertThat(
+                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -703,25 +753,26 @@
     @Test
     public void testNonModuleEnableRollback() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.MANAGE_ROLLBACKS);
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
 
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+            Install.single(TestApp.A2).setEnableRollback().commit();
 
             // We expect v2 of the app was installed, but rollback has not
             // been enabled because the test app is not a module.
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
-            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+            RollbackManager rm = RollbackUtils.getRollbackManager();
+            assertThat(
+                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -731,54 +782,53 @@
     @Test
     public void testMultiPackage() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
             // Prep installation of the test apps.
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.installMultiPackage(false,
-                    "RollbackTestAppAv1.apk",
-                    "RollbackTestAppBv1.apk");
-            processUserData(TEST_APP_A);
-            processUserData(TEST_APP_B);
-            RollbackTestUtils.installMultiPackage(true,
-                    "RollbackTestAppAv2.apk",
-                    "RollbackTestAppBv2.apk");
-            processUserData(TEST_APP_A);
-            processUserData(TEST_APP_B);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Uninstall.packages(TestApp.A, TestApp.B);
+            Install.multi(TestApp.A1, TestApp.B1).commit();
+            processUserData(TestApp.A);
+            processUserData(TestApp.B);
+            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
+            processUserData(TestApp.A);
+            processUserData(TestApp.B);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
-            // TEST_APP_A should now be available for rollback.
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoForAandB(rollback);
+            // TestApp.A should now be available for rollback.
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            assertThat(rollback).isNotNull();
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Rollback the app. It should cause both test apps to be rolled
             // back.
-            RollbackTestUtils.rollback(rollback.getRollbackId());
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            RollbackUtils.rollback(rollback.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
 
             // We should see recent rollbacks listed for both A and B.
             Thread.sleep(1000);
             RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
 
             RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_B);
-            assertRollbackInfoForAandB(rollbackB);
+                    rm.getRecentlyCommittedRollbacks(), TestApp.B);
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1),
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
-            assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
+            assertThat(rollbackA).hasRollbackId(rollbackB.getRollbackId());
 
-            processUserData(TEST_APP_A);
-            processUserData(TEST_APP_B);
+            processUserData(TestApp.A);
+            processUserData(TestApp.B);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -790,31 +840,27 @@
     @Test
     public void testMultiPackageEnableFail() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-
+            Uninstall.packages(TestApp.A, TestApp.B);
+            Install.single(TestApp.A1).commit();
             // We should fail to enable rollback here because TestApp B is not
             // already installed.
-            RollbackTestUtils.installMultiPackage(true,
-                    "RollbackTestAppAv2.apk",
-                    "RollbackTestAppBv2.apk");
+            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
 
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
-            assertNull(getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A));
-            assertNull(getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B));
+            assertThat(getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TestApp.A)).isNull();
+            assertThat(getUniqueRollbackInfoForPackage(
+                    rm.getAvailableRollbacks(), TestApp.B)).isNull();
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -825,30 +871,33 @@
      */
     public void testSameVersionUpdate() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            Install.single(TestApp.ACrashing2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback);
+                    rm.getAvailableRollbacks(), TestApp.A);
+            assertThat(rollback).isNotNull();
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A2));
 
-            RollbackTestUtils.rollback(rollback.getRollbackId());
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            RollbackUtils.rollback(rollback.getRollbackId());
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
             rollback = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 2, rollback);
+                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A2));
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -857,60 +906,54 @@
      */
     @Test
     public void testBadUpdateRollback() throws Exception {
-        BroadcastReceiver crashCountReceiver = null;
         Context context = InstrumentationRegistry.getContext();
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.MANAGE_ROLLBACKS,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
-                    Manifest.permission.KILL_BACKGROUND_PROCESSES,
+                    Manifest.permission.FORCE_STOP_PACKAGES,
                     Manifest.permission.RESTART_PACKAGES);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A, TestApp.B);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.ACrashing2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackTestUtils.uninstall(TEST_APP_B);
-            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            Install.single(TestApp.B1).commit();
+            Install.single(TestApp.B2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
 
             // Both test apps should now be available for rollback, and the
             // targetPackage returned for rollback should be correct.
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
+            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
+            assertThat(rollbackA).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_B);
-            assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
+            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
+            assertThat(rollbackB).packagesContainsExactly(
+                    Rollback.from(TestApp.B2).to(TestApp.B1));
 
             // Register rollback committed receiver
             RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
 
-            // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
-            crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
+            // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+            RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
 
             // Verify we received a broadcast for the rollback.
             rollbackReceiver.take();
 
-            // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
-            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // TestApp.A is automatically rolled back by the RollbackPackageHealthObserver
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
             // Instrumented app is still the package installer
-            String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A);
-            assertEquals(INSTRUMENTED_APP, installer);
-            // TEST_APP_B is untouched
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+            String installer = context.getPackageManager().getInstallerPackageName(TestApp.A);
+            assertThat(installer).isEqualTo(INSTRUMENTED_APP);
+            // TestApp.B is untouched
+            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
-            if (crashCountReceiver != null) {
-                context.unregisterReceiver(crashCountReceiver);
-            }
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -920,31 +963,31 @@
     @Test
     public void testRollForwardRace() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.MANAGE_ROLLBACKS);
 
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            Install.single(TestApp.A2).setEnableRollback().commit();
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
 
-            RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TEST_APP_A);
-            assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
+            assertThat(rollback).packagesContainsExactly(
+                    Rollback.from(TestApp.A2).to(TestApp.A1));
 
             // Install a new version of package A, then immediately rollback
             // the previous version. We expect the rollback to fail, because
             // it is no longer available.
             // There are a couple different ways this could fail depending on
             // thread interleaving, so don't ignore flaky failures.
-            RollbackTestUtils.install("RollbackTestAppAv3.apk", false);
+            Install.single(TestApp.A3).commit();
             try {
-                RollbackTestUtils.rollback(rollback.getRollbackId());
+                RollbackUtils.rollback(rollback.getRollbackId());
                 // Note: Don't ignore flaky failures here.
                 fail("Expected rollback to fail, but it did not.");
             } catch (AssertionError e) {
@@ -953,9 +996,9 @@
             }
 
             // Note: Don't ignore flaky failures here.
-            assertEquals(3, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(3);
         } finally {
-            RollbackTestUtils.dropShellPermissionIdentity();
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 
@@ -963,7 +1006,7 @@
     @Ignore("b/136605788")
     public void testEnableRollbackTimeoutFailsRollback() throws Exception {
         try {
-            RollbackTestUtils.adoptShellPermissionIdentity(
+            InstallUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.TEST_MANAGE_ROLLBACKS,
@@ -973,36 +1016,32 @@
             //setting the timeout to a very short amount that will definitely be triggered
             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
                     PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
-                    Long.toString(1), false /* makeDefault*/);
-            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+                    Long.toString(0), false /* makeDefault*/);
+            RollbackManager rm = RollbackUtils.getRollbackManager();
 
-            RollbackTestUtils.uninstall(TEST_APP_A);
-            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
-            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            Uninstall.packages(TestApp.A);
+            Install.single(TestApp.A1).commit();
+            waitForUnavailableRollback(TestApp.A);
 
-            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // Block the RollbackManager to make extra sure it will not be
+            // able to enable the rollback in time.
+            rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(1));
+            Install.single(TestApp.A2).setEnableRollback().commit();
 
-            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+
+            // Give plenty of time for RollbackManager to unblock and attempt
+            // to make the rollback available before asserting that the
+            // rollback was not made available.
+            Thread.sleep(TimeUnit.SECONDS.toMillis(2));
+            assertThat(
+                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
         } finally {
             //setting the timeout back to default
             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
                     PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
                     null, false /* makeDefault*/);
-            RollbackTestUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    // Helper function to test that the given rollback info is a rollback for
-    // the atomic set {A2, B2} -> {A1, B1}.
-    private void assertRollbackInfoForAandB(RollbackInfo rollback) {
-        assertNotNull(rollback);
-        assertEquals(2, rollback.getPackages().size());
-        if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) {
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0));
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1));
-        } else {
-            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0));
-            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1));
+            InstallUtils.dropShellPermissionIdentity();
         }
     }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
deleted file mode 100644
index a9e20cd..0000000
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.tests.rollback;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.RollbackInfo;
-import android.content.rollback.RollbackManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.SynchronousQueue;
-
-/**
- * Utilities to facilitate testing rollbacks.
- */
-class RollbackTestUtils {
-
-    private static final String TAG = "RollbackTest";
-
-    static RollbackManager getRollbackManager() {
-        Context context = InstrumentationRegistry.getContext();
-        RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
-        if (rm == null) {
-            throw new AssertionError("Failed to get RollbackManager");
-        }
-        return rm;
-    }
-
-    private static void setTime(long millis) {
-        Context context = InstrumentationRegistry.getContext();
-        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        am.setTime(millis);
-    }
-
-    static void forwardTimeBy(long offsetMillis) {
-        setTime(System.currentTimeMillis() + offsetMillis);
-        Log.i(TAG, "Forwarded time on device by " + offsetMillis + " millis");
-    }
-
-    /**
-     * Returns the version of the given package installed on device.
-     * Returns -1 if the package is not currently installed.
-     */
-    static long getInstalledVersion(String packageName) {
-        PackageInfo pi = getPackageInfo(packageName);
-        if (pi == null) {
-            return -1;
-        } else {
-            return pi.getLongVersionCode();
-        }
-    }
-
-    private static boolean isSystemAppWithoutUpdate(String packageName) {
-        PackageInfo pi = getPackageInfo(packageName);
-        if (pi == null) {
-            return false;
-        } else {
-            return ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
-                    && ((pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0);
-        }
-    }
-
-    private static PackageInfo getPackageInfo(String packageName) {
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager pm = context.getPackageManager();
-        try {
-            return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
-        } catch (PackageManager.NameNotFoundException e) {
-            return null;
-        }
-    }
-
-    private static void assertStatusSuccess(Intent result) {
-        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == -1) {
-            throw new AssertionError("PENDING USER ACTION");
-        } else if (status > 0) {
-            String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
-        }
-    }
-
-    /**
-     * Uninstalls the given package.
-     * Does nothing if the package is not installed.
-     * @throws AssertionError if package can't be uninstalled.
-     */
-    static void uninstall(String packageName) throws InterruptedException, IOException {
-        // No need to uninstall if the package isn't installed or is installed on /system.
-        if (getInstalledVersion(packageName) == -1 || isSystemAppWithoutUpdate(packageName)) {
-            return;
-        }
-
-        Context context = InstrumentationRegistry.getContext();
-        PackageManager packageManager = context.getPackageManager();
-        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
-        packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    /**
-     * Commit the given rollback.
-     * @throws AssertionError if the rollback fails.
-     */
-    static void rollback(int rollbackId, VersionedPackage... causePackages)
-            throws InterruptedException {
-        RollbackManager rm = getRollbackManager();
-        rm.commitRollback(rollbackId, Arrays.asList(causePackages),
-                LocalIntentSender.getIntentSender());
-        Intent result = LocalIntentSender.getIntentSenderResult();
-        int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
-                RollbackManager.STATUS_FAILURE);
-        if (status != RollbackManager.STATUS_SUCCESS) {
-            String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
-            throw new AssertionError(message);
-        }
-    }
-
-    /**
-     * Installs the apk with the given name.
-     *
-     * @param resourceName name of class loader resource for the apk to
-     *        install.
-     * @param enableRollback if rollback should be enabled.
-     * @throws AssertionError if the installation fails.
-     */
-    static void install(String resourceName, boolean enableRollback)
-            throws InterruptedException, IOException {
-        installSplit(enableRollback, resourceName);
-    }
-
-    /**
-     * Installs the apk with the given name and its splits.
-     *
-     * @param enableRollback if rollback should be enabled.
-     * @param resourceNames names of class loader resources for the apk and
-     *        its splits to install.
-     * @throws AssertionError if the installation fails.
-     */
-    static void installSplit(boolean enableRollback, String... resourceNames)
-            throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        PackageInstaller.Session session = null;
-        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        params.setEnableRollback(enableRollback);
-        int sessionId = packageInstaller.createSession(params);
-        session = packageInstaller.openSession(sessionId);
-
-        ClassLoader loader = RollbackTest.class.getClassLoader();
-        for (String resourceName : resourceNames) {
-            try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
-                    InputStream is = loader.getResourceAsStream(resourceName);) {
-                byte[] buffer = new byte[4096];
-                int n;
-                while ((n = is.read(buffer)) >= 0) {
-                    packageInSession.write(buffer, 0, n);
-                }
-            }
-        }
-
-        // Commit the session (this will start the installation workflow).
-        session.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-    }
-
-    /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
-    private static void launchPackage(String packageName)
-            throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setPackage(packageName);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addCategory(Intent.CATEGORY_LAUNCHER);
-        context.startActivity(intent);
-    }
-
-    /**
-     * Installs the APKs or APEXs with the given resource names as an atomic
-     * set. A resource is assumed to be an APEX if it has the .apex extension.
-     * <p>
-     * In case of staged installs, this function will return succesfully after
-     * the staged install has been committed and is ready for the device to
-     * reboot.
-     *
-     * @param staged if the rollback should be staged.
-     * @param enableRollback if rollback should be enabled.
-     * @param resourceNames names of the class loader resource for the apks to
-     *        install.
-     * @throws AssertionError if the installation fails.
-     */
-    private static void install(boolean staged, boolean enableRollback,
-            String... resourceNames) throws InterruptedException, IOException {
-        Context context = InstrumentationRegistry.getContext();
-        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
-
-        PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
-                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-        multiPackageParams.setMultiPackage();
-        if (staged) {
-            multiPackageParams.setStaged();
-        }
-        // TODO: Do we set this on the parent params, the child params, or
-        // both?
-        multiPackageParams.setEnableRollback(enableRollback);
-        int multiPackageId = packageInstaller.createSession(multiPackageParams);
-        PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
-
-        for (String resourceName : resourceNames) {
-            PackageInstaller.Session session = null;
-            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-            if (staged) {
-                params.setStaged();
-            }
-            if (resourceName.endsWith(".apex")) {
-                params.setInstallAsApex();
-            }
-            params.setEnableRollback(enableRollback);
-            int sessionId = packageInstaller.createSession(params);
-            session = packageInstaller.openSession(sessionId);
-
-            ClassLoader loader = RollbackTest.class.getClassLoader();
-            try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
-                 InputStream is = loader.getResourceAsStream(resourceName);) {
-                byte[] buffer = new byte[4096];
-                int n;
-                while ((n = is.read(buffer)) >= 0) {
-                    packageInSession.write(buffer, 0, n);
-                }
-            }
-            multiPackage.addChildSessionId(sessionId);
-        }
-
-        // Commit the session (this will start the installation workflow).
-        multiPackage.commit(LocalIntentSender.getIntentSender());
-        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
-
-        if (staged) {
-            waitForSessionReady(multiPackageId);
-        }
-    }
-
-    /**
-     * Installs the apks with the given resource names as an atomic set.
-     *
-     * @param enableRollback if rollback should be enabled.
-     * @param resourceNames names of the class loader resource for the apks to
-     *        install.
-     * @throws AssertionError if the installation fails.
-     */
-    static void installMultiPackage(boolean enableRollback, String... resourceNames)
-            throws InterruptedException, IOException {
-        install(false, enableRollback, resourceNames);
-    }
-
-    /**
-     * Installs the APKs or APEXs with the given resource names as a staged
-     * atomic set. A resource is assumed to be an APEX if it has the .apex
-     * extension.
-     *
-     * @param enableRollback if rollback should be enabled.
-     * @param resourceNames names of the class loader resource for the apks to
-     *        install.
-     * @throws AssertionError if the installation fails.
-     */
-    static void installStaged(boolean enableRollback, String... resourceNames)
-            throws InterruptedException, IOException {
-        install(true, enableRollback, resourceNames);
-    }
-
-    static void adoptShellPermissionIdentity(String... permissions) {
-        InstrumentationRegistry
-            .getInstrumentation()
-            .getUiAutomation()
-            .adoptShellPermissionIdentity(permissions);
-    }
-
-    static void dropShellPermissionIdentity() {
-        InstrumentationRegistry
-            .getInstrumentation()
-            .getUiAutomation()
-            .dropShellPermissionIdentity();
-    }
-
-    /**
-     * Returns the RollbackInfo with a given package in the list of rollbacks.
-     * Throws an assertion failure if there is more than one such rollback
-     * info. Returns null if there are no such rollback infos.
-     */
-    static RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
-            String packageName) {
-        RollbackInfo found = null;
-        for (RollbackInfo rollback : rollbacks) {
-            for (PackageRollbackInfo info : rollback.getPackages()) {
-                if (packageName.equals(info.getPackageName())) {
-                    assertNull(found);
-                    found = rollback;
-                    break;
-                }
-            }
-        }
-        return found;
-    }
-
-    /**
-     * Asserts that the given PackageRollbackInfo has the expected package
-     * name and versions.
-     */
-    static void assertPackageRollbackInfoEquals(String packageName,
-            long versionRolledBackFrom, long versionRolledBackTo,
-            PackageRollbackInfo info) {
-        assertEquals(packageName, info.getPackageName());
-        assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
-        assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
-        assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
-        assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
-    }
-
-    /**
-     * Asserts that the given RollbackInfo has the given packages with expected
-     * package names and all are rolled to and from the same given versions.
-     */
-    static void assertRollbackInfoEquals(String[] packageNames,
-            long versionRolledBackFrom, long versionRolledBackTo,
-            RollbackInfo info, VersionedPackage... causePackages) {
-        assertNotNull(info);
-        assertEquals(packageNames.length, info.getPackages().size());
-        int foundPackages = 0;
-        for (String packageName : packageNames) {
-            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
-                if (packageName.equals(pkgRollbackInfo.getPackageName())) {
-                    foundPackages++;
-                    assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom,
-                            versionRolledBackTo, pkgRollbackInfo);
-                    break;
-                }
-            }
-        }
-        assertEquals(packageNames.length, foundPackages);
-        assertEquals(causePackages.length, info.getCausePackages().size());
-        for (int i = 0; i < causePackages.length; ++i) {
-            assertEquals(causePackages[i].getPackageName(),
-                    info.getCausePackages().get(i).getPackageName());
-            assertEquals(causePackages[i].getLongVersionCode(),
-                    info.getCausePackages().get(i).getLongVersionCode());
-        }
-    }
-
-    /**
-     * Asserts that the given RollbackInfo has a single package with expected
-     * package name and versions.
-     */
-    static void assertRollbackInfoEquals(String packageName,
-            long versionRolledBackFrom, long versionRolledBackTo,
-            RollbackInfo info, VersionedPackage... causePackages) {
-        String[] packageNames = {packageName};
-        assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info,
-                causePackages);
-    }
-
-    /**
-     * Waits for the given session to be marked as ready.
-     * Throws an assertion if the session fails.
-     */
-    static void waitForSessionReady(int sessionId) {
-        BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
-        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                PackageInstaller.SessionInfo info =
-                        intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
-                if (info != null && info.getSessionId() == sessionId) {
-                    if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
-                        try {
-                            sessionStatus.put(info);
-                        } catch (InterruptedException e) {
-                            Log.e(TAG, "Failed to put session info.", e);
-                        }
-                    }
-                }
-            }
-        };
-        IntentFilter sessionUpdatedFilter =
-                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
-
-        Context context = InstrumentationRegistry.getContext();
-        context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
-
-        PackageInstaller installer = context.getPackageManager().getPackageInstaller();
-        PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
-
-        try {
-            if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
-                sessionStatus.put(info);
-            }
-
-            info = sessionStatus.take();
-            context.unregisterReceiver(sessionUpdatedReceiver);
-            if (info.isStagedSessionFailed()) {
-                throw new AssertionError(info.getStagedSessionErrorMessage());
-            }
-        } catch (InterruptedException e) {
-            throw new AssertionError(e);
-        }
-    }
-
-    private static final String NO_RESPONSE = "NO RESPONSE";
-
-    /**
-     * Calls into the test app to process user data.
-     * Asserts if the user data could not be processed or was version
-     * incompatible with the previously processed user data.
-     */
-    static void processUserData(String packageName) {
-        Intent intent = new Intent();
-        intent.setComponent(new ComponentName(packageName,
-                    "com.android.tests.rollback.testapp.ProcessUserData"));
-        Context context = InstrumentationRegistry.getContext();
-
-        HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
-        handlerThread.start();
-
-        // It can sometimes take a while after rollback before the app will
-        // receive this broadcast, so try a few times in a loop.
-        String result = NO_RESPONSE;
-        for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
-            BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
-            context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (getResultCode() == 1) {
-                        resultQueue.add("OK");
-                    } else {
-                        // If the test app doesn't receive the broadcast or
-                        // fails to set the result data, then getResultData
-                        // here returns the initial NO_RESPONSE data passed to
-                        // the sendOrderedBroadcast call.
-                        resultQueue.add(getResultData());
-                    }
-                }
-            }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
-
-            try {
-                result = resultQueue.take();
-            } catch (InterruptedException e) {
-                throw new AssertionError(e);
-            }
-        }
-
-        handlerThread.quit();
-        if (!"OK".equals(result)) {
-            fail(result);
-        }
-    }
-
-    /**
-     * Return the rollback info for a recently committed rollback, by matching the rollback id, or
-     * return null if no matching rollback is found.
-     */
-    static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) {
-        for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) {
-            if (info.getRollbackId() == getRollbackId) {
-                return info;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
-     * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
-     */
-    static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count)
-            throws InterruptedException, IOException {
-        BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
-        IntentFilter crashCountFilter = new IntentFilter();
-        crashCountFilter.addAction("com.android.tests.rollback.CRASH");
-        crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
-
-        BroadcastReceiver crashCountReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    try {
-                        // Sleep long enough for packagewatchdog to be notified of crash
-                        Thread.sleep(1000);
-                        // Kill app and close AppErrorDialog
-                        ActivityManager am = context.getSystemService(ActivityManager.class);
-                        am.killBackgroundProcesses(packageName);
-                        // Allow another package launch
-                        crashQueue.put(intent.getIntExtra("count", 0));
-                    } catch (InterruptedException e) {
-                        fail("Failed to communicate with test app");
-                    }
-                }
-            };
-        context.registerReceiver(crashCountReceiver, crashCountFilter);
-
-        do {
-            launchPackage(packageName);
-        } while(crashQueue.take() < count);
-        return crashCountReceiver;
-    }
-}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 1a29c4c..9e6ac8e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -16,26 +16,34 @@
 
 package com.android.tests.rollback;
 
-import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
-import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
 
 import android.Manifest;
-import android.content.BroadcastReceiver;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.VersionedPackage;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
+import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.install.lib.Uninstall;
+import com.android.cts.rollback.lib.Rollback;
+import com.android.cts.rollback.lib.RollbackUtils;
+import com.android.internal.R;
 
 import org.junit.After;
 import org.junit.Before;
@@ -54,23 +62,21 @@
 @RunWith(JUnit4.class)
 public class StagedRollbackTest {
 
-    private static final String TAG = "RollbackTest";
-    private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
-    private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk";
-    private static final String TEST_APP_A_CRASHING_V2 = "RollbackTestAppACrashingV2.apk";
     private static final String NETWORK_STACK_CONNECTOR_CLASS =
             "android.net.INetworkStackConnector";
 
+    private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
+
     /**
      * Adopts common shell permissions needed for rollback tests.
      */
     @Before
     public void adoptShellPermissions() {
-        RollbackTestUtils.adoptShellPermissionIdentity(
+        InstallUtils.adoptShellPermissionIdentity(
                 Manifest.permission.INSTALL_PACKAGES,
                 Manifest.permission.DELETE_PACKAGES,
                 Manifest.permission.TEST_MANAGE_ROLLBACKS,
-                Manifest.permission.KILL_BACKGROUND_PROCESSES);
+                Manifest.permission.FORCE_STOP_PACKAGES);
     }
 
     /**
@@ -78,7 +84,7 @@
      */
     @After
     public void dropShellPermissions() {
-        RollbackTestUtils.dropShellPermissionIdentity();
+        InstallUtils.dropShellPermissionIdentity();
     }
 
     /**
@@ -87,14 +93,14 @@
      */
     @Test
     public void testBadApkOnlyEnableRollback() throws Exception {
-        RollbackTestUtils.uninstall(TEST_APP_A);
-        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+        Uninstall.packages(TestApp.A);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
 
-        RollbackTestUtils.install(TEST_APP_A_V1, false);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-        RollbackTestUtils.processUserData(TEST_APP_A);
+        Install.single(TestApp.A1).commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
 
-        RollbackTestUtils.installStaged(true, TEST_APP_A_CRASHING_V2);
+        Install.single(TestApp.ACrashing2).setEnableRollback().setStaged().commit();
 
         // At this point, the host test driver will reboot the device and run
         // testBadApkOnlyConfirmEnableRollback().
@@ -106,14 +112,16 @@
      */
     @Test
     public void testBadApkOnlyConfirmEnableRollback() throws Exception {
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-        RollbackTestUtils.processUserData(TEST_APP_A);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.processUserData(TestApp.A);
 
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
         RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                rm.getAvailableRollbacks(), TEST_APP_A);
-        assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
-        assertTrue(rollback.isStaged());
+                rm.getAvailableRollbacks(), TestApp.A);
+        assertThat(rollback).isNotNull();
+        assertThat(rollback).packagesContainsExactly(
+                Rollback.from(TestApp.A2).to(TestApp.A1));
+        assertThat(rollback.isStaged()).isTrue();
 
         // At this point, the host test driver will run
         // testBadApkOnlyTriggerRollback().
@@ -126,18 +134,8 @@
      */
     @Test
     public void testBadApkOnlyTriggerRollback() throws Exception {
-        BroadcastReceiver crashCountReceiver = null;
-        Context context = InstrumentationRegistry.getContext();
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-
-        try {
-            // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
-            crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
-        } finally {
-            if (crashCountReceiver != null) {
-                context.unregisterReceiver(crashCountReceiver);
-            }
-        }
+        // Crash TestApp.A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+        RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
 
         // We expect the device to be rebooted automatically. Wait for that to
         // happen. At that point, the host test driver will wait for the
@@ -153,48 +151,80 @@
      */
     @Test
     public void testBadApkOnlyConfirmRollback() throws Exception {
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
-        RollbackTestUtils.processUserData(TEST_APP_A);
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
 
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
         RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
-        assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback, new VersionedPackage(TEST_APP_A, 2));
-        assertTrue(rollback.isStaged());
-        assertNotEquals(-1, rollback.getCommittedSessionId());
+                rm.getRecentlyCommittedRollbacks(), TestApp.A);
+        assertThat(rollback).isNotNull();
+        assertThat(rollback).packagesContainsExactly(
+                Rollback.from(TestApp.A2).to(TestApp.A1));
+        assertThat(rollback).causePackagesContainsExactly(TestApp.ACrashing2);
+        assertThat(rollback).isStaged();
+        assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
     }
 
     @Test
     public void resetNetworkStack() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackManager rm = RollbackUtils.getRollbackManager();
         String networkStack = getNetworkStackPackageName();
 
         rm.expireRollbackForPackage(networkStack);
-        RollbackTestUtils.uninstall(networkStack);
+        Uninstall.packages(networkStack);
 
-        assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
-                        networkStack));
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                        networkStack)).isNull();
+    }
+
+    @Test
+    public void installModuleMetadataPackage() throws Exception {
+        resetModuleMetadataPackage();
+        Context context = InstrumentationRegistry.getContext();
+        PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo(
+                MODULE_META_DATA_PACKAGE, 0);
+        String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir;
+        assertThat(metadataApkPath).isNotNull();
+        assertThat(metadataApkPath).isNotEqualTo("");
+
+        runShellCommand("pm install "
+                + "-r --enable-rollback --staged --wait "
+                + metadataApkPath);
     }
 
     @Test
     public void assertNetworkStackRollbackAvailable() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-        assertNotNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
-                        getNetworkStackPackageName()));
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                        getNetworkStackPackageName())).isNotNull();
     }
 
     @Test
     public void assertNetworkStackRollbackCommitted() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-        assertNotNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        getNetworkStackPackageName()));
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                        getNetworkStackPackageName())).isNotNull();
     }
 
     @Test
     public void assertNoNetworkStackRollbackCommitted() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-        assertNull(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        getNetworkStackPackageName()));
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                        getNetworkStackPackageName())).isNull();
+    }
+
+    @Test
+    public void assertModuleMetadataRollbackAvailable() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                        MODULE_META_DATA_PACKAGE)).isNotNull();
+    }
+
+    @Test
+    public void assertModuleMetadataRollbackCommitted() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                        MODULE_META_DATA_PACKAGE)).isNotNull();
     }
 
     private String getNetworkStackPackageName() {
@@ -203,4 +233,65 @@
                 InstrumentationRegistry.getContext().getPackageManager(), 0);
         return comp.getPackageName();
     }
+
+    @Test
+    public void testPreviouslyAbandonedRollbacksEnableRollback() throws Exception {
+        Uninstall.packages(TestApp.A);
+        Install.single(TestApp.A1).commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+        int sessionId = Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+        PackageInstaller pi = InstrumentationRegistry.getContext().getPackageManager()
+                .getPackageInstaller();
+        pi.abandonSession(sessionId);
+
+        // Remove the first intent sender result, so that the next staged install session does not
+        // erroneously think that it has itself been abandoned.
+        // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
+        LocalIntentSender.getIntentSenderResult();
+        Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+    }
+
+    @Test
+    public void testPreviouslyAbandonedRollbacksCommitRollback() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+        InstallUtils.processUserData(TestApp.A);
+
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TestApp.A);
+        RollbackUtils.rollback(rollback.getRollbackId());
+    }
+
+    @Test
+    public void testPreviouslyAbandonedRollbacksCheckUserdataRollback() throws Exception {
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+        InstallUtils.processUserData(TestApp.A);
+        Uninstall.packages(TestApp.A);
+    }
+
+    @Nullable
+    private static String getModuleMetadataPackageName() {
+        String packageName = InstrumentationRegistry.getContext().getResources().getString(
+                R.string.config_defaultModuleMetadataProvider);
+        if (TextUtils.isEmpty(packageName)) {
+            return null;
+        }
+        return packageName;
+    }
+
+    private void resetModuleMetadataPackage() {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+
+        assertThat(MODULE_META_DATA_PACKAGE).isNotNull();
+        rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE);
+
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                MODULE_META_DATA_PACKAGE)).isNull();
+    }
+
+    private void runShellCommand(String cmd) {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .executeShellCommand(cmd);
+    }
 }
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index b767b08..f74aaf3 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -29,11 +29,15 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Runs the staged rollback tests.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class StagedRollbackTest extends BaseHostJUnit4Test {
+    private static final int NATIVE_CRASHES_THRESHOLD = 5;
+
     /**
      * Runs the given phase of a test by calling into the device.
      * Throws an exception if the test phase fails.
@@ -84,6 +88,35 @@
         runPhase("testBadApkOnlyConfirmRollback");
     }
 
+    @Test
+    public void testNativeWatchdogTriggersRollback() throws Exception {
+        //Stage install ModuleMetadata package - this simulates a Mainline module update
+        runPhase("installModuleMetadataPackage");
+
+        // Reboot device to activate staged package
+        getDevice().reboot();
+        getDevice().waitForDeviceAvailable();
+
+        runPhase("assertModuleMetadataRollbackAvailable");
+
+        // crash system_server enough times to trigger a rollback
+        crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
+
+        // Rollback should be committed automatically now.
+        // Give time for rollback to be committed. This could take a while,
+        // because we need all of the following to happen:
+        // 1. system_server comes back up and boot completes.
+        // 2. Rollback health observer detects updatable crashing signal.
+        // 3. Staged rollback session becomes ready.
+        // 4. Device actually reboots.
+        // So we give a generous timeout here.
+        assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+        getDevice().waitForDeviceAvailable();
+
+        // verify rollback committed
+        runPhase("assertModuleMetadataRollbackCommitted");
+    }
+
     /**
      * Tests failed network health check triggers watchdog staged rollbacks.
      */
@@ -167,6 +200,32 @@
         runPhase("assertNoNetworkStackRollbackCommitted");
     }
 
+    /**
+     * Tests rolling back user data where there are multiple rollbacks for that package.
+     */
+    @Test
+    public void testPreviouslyAbandonedRollbacks() throws Exception {
+        runPhase("testPreviouslyAbandonedRollbacksEnableRollback");
+        getDevice().reboot();
+        runPhase("testPreviouslyAbandonedRollbacksCommitRollback");
+        getDevice().reboot();
+        runPhase("testPreviouslyAbandonedRollbacksCheckUserdataRollback");
+    }
+
+    private void crashProcess(String processName, int numberOfCrashes) throws Exception {
+        String pid = "";
+        String lastPid = "invalid";
+        for (int i = 0; i < numberOfCrashes; ++i) {
+            // This condition makes sure before we kill the process, the process is running AND
+            // the last crash was finished.
+            while ("".equals(pid) || lastPid.equals(pid)) {
+                pid = getDevice().executeShellCommand("pidof " + processName);
+            }
+            getDevice().executeShellCommand("kill " + pid);
+            lastPid = pid;
+        }
+    }
+
     private String getNetworkStackPath() throws DeviceNotAvailableException {
         // Find the NetworkStack path (can be NetworkStack.apk or NetworkStackNext.apk)
         return getDevice().executeShellCommand("ls /system/priv-app/NetworkStack*/*.apk");
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
index 6be93a0..fefde5b 100644
--- a/tests/RollbackTest/TEST_MAPPING
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -5,6 +5,9 @@
     },
     {
       "name": "StagedRollbackTest"
+    },
+    {
+      "name": "MultiUserRollbackTest"
     }
   ]
 }
diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml
deleted file mode 100644
index 77bfd4e..0000000
--- a/tests/RollbackTest/TestApp/ACrashingV2.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.A"
-    android:versionCode="2"
-    android:versionName="2.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App A v2">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
-            <intent-filter>
-              <action android:name="android.intent.action.MAIN" />
-              <category android:name="android.intent.category.DEFAULT"/>
-              <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml
deleted file mode 100644
index 63729fb..0000000
--- a/tests/RollbackTest/TestApp/Av1.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.A"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App A v1">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml
deleted file mode 100644
index f0e909f..0000000
--- a/tests/RollbackTest/TestApp/Av2.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.A"
-    android:versionCode="2"
-    android:versionName="2.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App A v2">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av3.xml b/tests/RollbackTest/TestApp/Av3.xml
deleted file mode 100644
index 9725c9f7..0000000
--- a/tests/RollbackTest/TestApp/Av3.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.A"
-    android:versionCode="3"
-    android:versionName="3.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App A v3">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml
deleted file mode 100644
index ca9c2ec..0000000
--- a/tests/RollbackTest/TestApp/Bv1.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.B"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App B v1">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml
deleted file mode 100644
index bd3e613..0000000
--- a/tests/RollbackTest/TestApp/Bv2.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp.B"
-    android:versionCode="2"
-    android:versionName="2.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App B v2">
-        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
-                  android:exported="true" />
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
deleted file mode 100644
index 90d3da2..0000000
--- a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="split_version">1</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v1/values/values.xml b/tests/RollbackTest/TestApp/res_v1/values/values.xml
deleted file mode 100644
index 0447c74..0000000
--- a/tests/RollbackTest/TestApp/res_v1/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="app_version">1</integer>
-    <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
deleted file mode 100644
index 9a1aa7f..0000000
--- a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="split_version">2</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values/values.xml b/tests/RollbackTest/TestApp/res_v2/values/values.xml
deleted file mode 100644
index fd988f5..0000000
--- a/tests/RollbackTest/TestApp/res_v2/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="app_version">2</integer>
-    <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml
deleted file mode 100644
index f2d8992..0000000
--- a/tests/RollbackTest/TestApp/res_v3/values-anydpi/values.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="split_version">3</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/res_v3/values/values.xml b/tests/RollbackTest/TestApp/res_v3/values/values.xml
deleted file mode 100644
index 968168a..0000000
--- a/tests/RollbackTest/TestApp/res_v3/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <integer name="app_version">3</integer>
-    <integer name="split_version">0</integer>
-</resources>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
deleted file mode 100644
index 97958ac..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tests.rollback.testapp;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-
-/**
- * A crashing test app for testing apk rollback support.
- */
-public class CrashingMainActivity extends Activity {
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        incrementCountAndBroadcast();
-        throw new RuntimeException("Intended force crash");
-    }
-
-    private void incrementCountAndBroadcast() {
-        SharedPreferences preferences = getSharedPreferences("prefs", Context.MODE_PRIVATE);
-        SharedPreferences.Editor editor = preferences.edit();
-        int count = preferences.getInt("crash_count", 0);
-        editor.putInt("crash_count", ++count).commit();
-
-        Intent intent = new Intent("com.android.tests.rollback.CRASH");
-        intent.putExtra("count", count);
-        sendBroadcast(intent);
-    }
-}
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
deleted file mode 100644
index 9f1a060..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.tests.rollback.testapp;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * A test app for testing apk rollback support.
- */
-public class MainActivity extends Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        try {
-            new ProcessUserData().processUserData(this);
-        } catch (ProcessUserData.UserDataException e) {
-            throw new AssertionError("Failed to process app user data", e);
-        }
-    }
-}
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
deleted file mode 100644
index 38c658e..0000000
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.tests.rollback.testapp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Scanner;
-
-/**
- * A broadcast reciever to check for and update user app data version
- * compatibility.
- */
-public class ProcessUserData extends BroadcastReceiver {
-
-    private static final String TAG = "RollbackTestApp";
-
-    /**
-     * Exception thrown in case of issue with user data.
-     */
-    public static class UserDataException extends Exception {
-        public UserDataException(String message) {
-            super(message);
-        }
-
-        public UserDataException(String message, Throwable cause) {
-           super(message, cause);
-        }
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        try {
-            processUserData(context);
-            setResultCode(1);
-        } catch (UserDataException e) {
-            setResultCode(0);
-            setResultData(e.getMessage());
-        }
-    }
-
-    /**
-     * Update the app's user data version to match the app version.
-     *
-     * @param context The application context.
-     * @throws UserDataException in case of problems with app user data.
-     */
-    public void processUserData(Context context) throws UserDataException {
-        Resources res = context.getResources();
-        String packageName = context.getPackageName();
-
-        int appVersionId = res.getIdentifier("app_version", "integer", packageName);
-        int appVersion = res.getInteger(appVersionId);
-
-        int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
-        int splitVersion = res.getInteger(splitVersionId);
-
-        // Make sure the app version and split versions are compatible.
-        if (appVersion != splitVersion) {
-            throw new UserDataException("Split version " + splitVersion
-                    + " does not match app version " + appVersion);
-        }
-
-        // Read the version of the app's user data and ensure it is compatible
-        // with our version of the application.
-        File versionFile = new File(context.getFilesDir(), "version.txt");
-        try {
-            Scanner s = new Scanner(versionFile);
-            int userDataVersion = s.nextInt();
-            s.close();
-
-            if (userDataVersion > appVersion) {
-                throw new UserDataException("User data is from version " + userDataVersion
-                        + ", which is not compatible with this version " + appVersion
-                        + " of the RollbackTestApp");
-            }
-        } catch (FileNotFoundException e) {
-            // No problem. This is a fresh install of the app or the user data
-            // has been wiped.
-        }
-
-        // Record the current version of the app in the user data.
-        try {
-            PrintWriter pw = new PrintWriter(versionFile);
-            pw.println(appVersion);
-            pw.close();
-        } catch (IOException e) {
-            throw new UserDataException("Unable to write user data.", e);
-        }
-    }
-}
diff --git a/tests/net/java/android/net/ip/InterfaceControllerTest.java b/tests/net/java/android/net/ip/InterfaceControllerTest.java
deleted file mode 100644
index 7a56b3a..0000000
--- a/tests/net/java/android/net/ip/InterfaceControllerTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.net.INetd;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.LinkAddress;
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InterfaceControllerTest {
-    private static final String TEST_IFACE = "testif";
-    private static final String TEST_IPV4_ADDR = "192.168.123.28";
-    private static final int TEST_PREFIXLENGTH = 31;
-
-    @Mock private INetd mNetd;
-    @Mock private SharedLog mLog;
-    @Captor private ArgumentCaptor<InterfaceConfigurationParcel> mConfigCaptor;
-
-    private InterfaceController mController;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mController = new InterfaceController(TEST_IFACE, mNetd, mLog);
-
-        doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture());
-    }
-
-    @Test
-    public void testSetIPv4Address() throws Exception {
-        mController.setIPv4Address(
-                new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR),
-                        TEST_PREFIXLENGTH));
-        verify(mNetd, times(1)).interfaceSetCfg(any());
-        final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
-        assertEquals(TEST_IFACE, parcel.ifName);
-        assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr);
-        assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength);
-        assertEquals("", parcel.hwAddr);
-        assertArrayEquals(new String[0], parcel.flags);
-    }
-
-    @Test
-    public void testClearIPv4Address() throws Exception {
-        mController.clearIPv4Address();
-        verify(mNetd, times(1)).interfaceSetCfg(any());
-        final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue();
-        assertEquals(TEST_IFACE, parcel.ifName);
-        assertEquals("0.0.0.0", parcel.ipv4Addr);
-        assertEquals(0, parcel.prefixLength);
-        assertEquals("", parcel.hwAddr);
-        assertArrayEquals(new String[0], parcel.flags);
-    }
-}
diff --git a/tests/net/java/android/net/netlink/ConntrackMessageTest.java b/tests/net/java/android/net/netlink/ConntrackMessageTest.java
deleted file mode 100644
index 5c86757..0000000
--- a/tests/net/java/android/net/netlink/ConntrackMessageTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assume.assumeTrue;
-
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConntrackMessageTest {
-    private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
-
-    // Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443)
-    public static final String CT_V4UPDATE_TCP_HEX =
-            // struct nlmsghdr
-            "50000000" +      // length = 80
-            "0001" +          // type = (1 << 8) | 0
-            "0501" +          // flags
-            "01000000" +      // seqno = 1
-            "00000000" +      // pid = 0
-            // struct nfgenmsg
-            "02" +            // nfgen_family  = AF_INET
-            "00" +            // version = NFNETLINK_V0
-            "0000" +          // res_id
-            // struct nlattr
-            "3400" +          // nla_len = 52
-            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 C0A82BD1" +  // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209
-                    "0800 0200 17D30D1A" +  // nla_type=CTA_IP_V4_DST, ip=23.211.13.26
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 06 000000" +  // nla_type=CTA_PROTO_NUM, proto=6
-                    "0600 0200 AD2D 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian)
-                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0700" +          // nla_type = CTA_TIMEOUT
-            "00069780";       // nla_value = 432000 (big endian)
-    public static final byte[] CT_V4UPDATE_TCP_BYTES =
-            HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    // Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443)
-    public static final String CT_V4UPDATE_UDP_HEX =
-            // struct nlmsghdr
-            "50000000" +      // length = 80
-            "0001" +          // type = (1 << 8) | 0
-            "0501" +          // flags
-            "01000000" +      // seqno = 1
-            "00000000" +      // pid = 0
-            // struct nfgenmsg
-            "02" +            // nfgen_family  = AF_INET
-            "00" +            // version = NFNETLINK_V0
-            "0000" +          // res_id
-            // struct nlattr
-            "3400" +          // nla_len = 52
-            "0180" +          // nla_type = nested CTA_TUPLE_ORIG
-                // struct nlattr
-                "1400" +      // nla_len = 20
-                "0180" +      // nla_type = nested CTA_TUPLE_IP
-                    "0800 0100 6460A792" +  // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146
-                    "0800 0200 D83AC50A" +  // nla_type=CTA_IP_V4_DST, ip=216.58.197.10
-                // struct nlattr
-                "1C00" +      // nla_len = 28
-                "0280" +      // nla_type = nested CTA_TUPLE_PROTO
-                    "0500 0100 11 000000" +  // nla_type=CTA_PROTO_NUM, proto=17
-                    "0600 0200 90CD 0000" +  // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian)
-                    "0600 0300 01BB 0000" +  // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian)
-            // struct nlattr
-            "0800" +          // nla_len = 8
-            "0700" +          // nla_type = CTA_TIMEOUT
-            "000000B4";       // nla_value = 180 (big endian)
-    public static final byte[] CT_V4UPDATE_UDP_BYTES =
-            HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    @Test
-    public void testConntrackIPv4TcpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] tcp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
-                OsConstants.IPPROTO_TCP,
-                (Inet4Address) InetAddress.getByName("192.168.43.209"), 44333,
-                (Inet4Address) InetAddress.getByName("23.211.13.26"), 443,
-                432000);
-        assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp);
-    }
-
-    @Test
-    public void testConntrackIPv4UdpTimeoutUpdate() throws Exception {
-        assumeTrue(USING_LE);
-
-        final byte[] udp = ConntrackMessage.newIPv4TimeoutUpdateRequest(
-                OsConstants.IPPROTO_UDP,
-                (Inet4Address) InetAddress.getByName("100.96.167.146"), 37069,
-                (Inet4Address) InetAddress.getByName("216.58.197.10"), 443,
-                180);
-        assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp);
-    }
-}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
deleted file mode 100644
index 84c5784..0000000
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * 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.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.netlink.StructNlMsgHdr;
-import android.os.Process;
-import android.system.Os;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InetDiagSocketTest {
-    private final String TAG = "InetDiagSocketTest";
-    private ConnectivityManager mCm;
-    private Context mContext;
-    private final static int SOCKET_TIMEOUT_MS = 100;
-
-    @Before
-    public void setUp() throws Exception {
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        mContext = instrumentation.getTargetContext();
-        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-    }
-
-    private class Connection {
-        public int socketDomain;
-        public int socketType;
-        public InetAddress localAddress;
-        public InetAddress remoteAddress;
-        public InetAddress localhostAddress;
-        public InetSocketAddress local;
-        public InetSocketAddress remote;
-        public int protocol;
-        public FileDescriptor localFd;
-        public FileDescriptor remoteFd;
-
-        public FileDescriptor createSocket() throws Exception {
-            return Os.socket(socketDomain, socketType, protocol);
-        }
-
-        public Connection(String to, String from) throws Exception {
-            remoteAddress = InetAddress.getByName(to);
-            if (from != null) {
-                localAddress = InetAddress.getByName(from);
-            } else {
-                localAddress = (remoteAddress instanceof Inet4Address) ?
-                        Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
-            }
-            if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
-                socketDomain = AF_INET;
-                localhostAddress = Inet4Address.getByName("localhost");
-            } else {
-                socketDomain = AF_INET6;
-                localhostAddress = Inet6Address.getByName("::");
-            }
-        }
-
-        public void close() throws Exception {
-            Os.close(localFd);
-        }
-    }
-
-    private class TcpConnection extends Connection {
-        public TcpConnection(String to, String from) throws Exception {
-            super(to, from);
-            protocol = IPPROTO_TCP;
-            socketType = SOCK_STREAM;
-
-            remoteFd = createSocket();
-            Os.bind(remoteFd, remoteAddress, 0);
-            Os.listen(remoteFd, 10);
-            int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
-
-            localFd = createSocket();
-            Os.bind(localFd, localAddress, 0);
-            Os.connect(localFd, remoteAddress, remotePort);
-
-            local = (InetSocketAddress) Os.getsockname(localFd);
-            remote = (InetSocketAddress) Os.getpeername(localFd);
-        }
-
-        public void close() throws Exception {
-            super.close();
-            Os.close(remoteFd);
-        }
-    }
-    private class UdpConnection extends Connection {
-        public UdpConnection(String to, String from) throws Exception {
-            super(to, from);
-            protocol = IPPROTO_UDP;
-            socketType = SOCK_DGRAM;
-
-            remoteFd = null;
-            localFd = createSocket();
-            Os.bind(localFd, localAddress, 0);
-
-            Os.connect(localFd, remoteAddress, 7);
-            local = (InetSocketAddress) Os.getsockname(localFd);
-            remote = new InetSocketAddress(remoteAddress, 7);
-        }
-    }
-
-    private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
-                                         InetSocketAddress remote, boolean expectSuccess) {
-        final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
-
-        if (expectSuccess) {
-            assertEquals(Process.myUid(), uid);
-        } else {
-            assertNotEquals(Process.myUid(), uid);
-        }
-    }
-
-    private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
-        UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
-                conn.localAddress.getHostAddress());
-        final int localPort = udp.local.getPort();
-        udp.close();
-        return localPort;
-    }
-
-    /**
-     * Create a test connection for UDP and TCP sockets and verify that this
-     * {protocol, local, remote} socket result in receiving a valid UID.
-     */
-    public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
-        TcpConnection tcp = new TcpConnection(to, from);
-        checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
-        checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
-        checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
-        checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
-        tcp.close();
-
-        UdpConnection udp = new UdpConnection(to,from);
-        checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
-        checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
-        checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
-                udp.remote, false);
-        udp.close();
-    }
-
-    @Test
-    public void testGetConnectionOwnerUid() throws Exception {
-        checkGetConnectionOwnerUid("::", null);
-        checkGetConnectionOwnerUid("::", "::");
-        checkGetConnectionOwnerUid("0.0.0.0", null);
-        checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
-        checkGetConnectionOwnerUid("127.0.0.1", null);
-        checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
-        checkGetConnectionOwnerUid("::1", null);
-        checkGetConnectionOwnerUid("::1", "::1");
-    }
-
-    /* Verify fix for b/141603906 */
-    @Test
-    public void testB141603906() throws Exception {
-        final InetSocketAddress src = new InetSocketAddress(0);
-        final InetSocketAddress dst = new InetSocketAddress(0);
-        final int numThreads = 8;
-        final int numSockets = 5000;
-        final Thread[] threads = new Thread[numThreads];
-
-        for (int i = 0; i < numThreads; i++) {
-            threads[i] = new Thread(() -> {
-                for (int j = 0; j < numSockets; j++) {
-                    mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
-                }
-            });
-        }
-
-        for (Thread thread : threads) {
-            thread.start();
-        }
-
-        for (Thread thread : threads) {
-            thread.join();
-        }
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0103" +         // flags = NLM_F_REQUEST | NLM_F_DUMP
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "02" +           // family = AF_INET
-            "11" +           // protcol = IPPROTO_UDP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-            // inet_diag_sockid
-            "a5de" +         // idiag_sport = 42462
-            "b971" +         // idiag_dport = 47473
-            "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
-            "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
-            "00000000" +     // idiag_if
-            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-    private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2UdpInet4() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
-                42462);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
-                (short) (NLM_F_REQUEST | NLM_F_DUMP));
-        assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "0a" +           // family = AF_INET6
-            "06" +           // protcol = IPPROTO_TCP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-                // inet_diag_sockid
-                "a5de" +         // idiag_sport = 42462
-                "b971" +         // idiag_dport = 47473
-                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
-                "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
-                "00000000" +     // idiag_if
-                "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2TcpInet6() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
-                NLM_F_REQUEST);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
-    private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "02" +           // family = AF_INET
-            "06" +           // protcol = IPPROTO_TCP
-            "02" +           // idiag_ext = INET_DIAG_INFO
-            "00" +           // pad
-            "ffffffff" +   // idiag_states
-            // inet_diag_sockid
-            "3039" +         // idiag_sport = 12345
-            "d431" +         // idiag_dport = 54321
-            "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
-            "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
-            "00000000" +     // idiag_if
-            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
-
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
-    private static final int TCP_ALL_STATES = 0xffffffff;
-    @Test
-    public void testInetDiagReqV2TcpInetWithExt() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("1.2.3.4"), 12345);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
-                54321);
-        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
-                NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
-
-        local = new InetSocketAddress(
-                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
-        remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
-                47473);
-        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
-    private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
-            // struct nlmsghdr
-            "48000000" +     // length = 72
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0100" +         // flags = NLM_F_REQUEST
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct inet_diag_req_v2
-            "0a" +           // family = AF_INET6
-            "06" +           // protcol = IPPROTO_TCP
-            "00" +           // idiag_ext
-            "00" +           // pad
-            "ffffffff" +     // idiag_states
-            // inet_diag_sockid
-            "0000" +         // idiag_sport
-            "0000" +         // idiag_dport
-            "00000000000000000000000000000000" + // idiag_src
-            "00000000000000000000000000000000" + // idiag_dst
-            "00000000" +     // idiag_if
-            "0000000000000000"; // idiag_cookie
-
-    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
-            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
-
-    @Test
-    public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
-        InetSocketAddress local = new InetSocketAddress(
-                InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
-        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
-                54321);
-        // Verify no socket specified if either local or remote socket address is null.
-        byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-        byte[] msg;
-        try {
-            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
-                    NLM_F_REQUEST);
-            fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
-                    NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-            fail("Both remote and local should be null, expected UnknownHostException");
-        } catch (NullPointerException e) {
-        }
-
-        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
-                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
-        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
-    }
-
-    // Hexadecimal representation of InetDiagReqV2 request.
-    private static final String INET_DIAG_MSG_HEX =
-            // struct nlmsghdr
-            "58000000" +     // length = 88
-            "1400" +         // type = SOCK_DIAG_BY_FAMILY
-            "0200" +         // flags = NLM_F_MULTI
-            "00000000" +     // seqno
-            "f5220000" +     // pid (0 == kernel)
-            // struct inet_diag_msg
-            "0a" +           // family = AF_INET6
-            "01" +           // idiag_state
-            "00" +           // idiag_timer
-            "00" +           // idiag_retrans
-                // inet_diag_sockid
-                "a817" +     // idiag_sport = 43031
-                "960f" +     // idiag_dport = 38415
-                "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
-                "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
-                "00000000" + // idiag_if
-                "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
-            "00000000" +     // idiag_expires
-            "00000000" +     // idiag_rqueue
-            "00000000" +     // idiag_wqueue
-            "a3270000" +     // idiag_uid
-            "A57E1900";      // idiag_inode
-    private static final byte[] INET_DIAG_MSG_BYTES =
-            HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
-
-    @Test
-    public void testParseInetDiagResponse() throws Exception {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
-        assertNotNull(msg);
-
-        assertTrue(msg instanceof InetDiagMessage);
-        final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
-        assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
-
-        final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
-        assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(8949, hdr.nlmsg_pid);
-    }
-}
diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
deleted file mode 100644
index 44ab605..0000000
--- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.StructNlMsgErr;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkErrorMessageTest {
-    private final String TAG = "NetlinkErrorMessageTest";
-
-    // Hexadecimal representation of packet capture.
-    public static final String NLM_ERROR_OK_HEX =
-            // struct nlmsghdr
-            "24000000" +     // length = 36
-            "0200"     +     // type = 2 (NLMSG_ERROR)
-            "0000"     +     // flags
-            "26350000" +     // seqno
-            "64100000" +     // pid = userspace process
-            // error integer
-            "00000000" +     // "errno" (0 == OK)
-            // struct nlmsghdr
-            "30000000" +     // length (48) of original request
-            "1C00"     +     // type = 28 (RTM_NEWNEIGH)
-            "0501"     +     // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
-            "26350000" +     // seqno
-            "00000000";      // pid = kernel
-    public static final byte[] NLM_ERROR_OK =
-            HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
-
-    @Test
-    public void testParseNlmErrorOk() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
-        assertNotNull(msg);
-        assertTrue(msg instanceof NetlinkErrorMessage);
-        final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
-
-        final StructNlMsgHdr hdr = errorMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(36, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(13606, hdr.nlmsg_seq);
-        assertEquals(4196, hdr.nlmsg_pid);
-
-        final StructNlMsgErr err = errorMsg.getNlMsgError();
-        assertNotNull(err);
-        assertEquals(0, err.error);
-        assertNotNull(err.msg);
-        assertEquals(48, err.msg.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
-        assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
-        assertEquals(13606, err.msg.nlmsg_seq);
-        assertEquals(0, err.msg.nlmsg_pid);
-    }
-}
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
deleted file mode 100644
index 3916578..0000000
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
-import static android.system.OsConstants.NETLINK_ROUTE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.NetlinkSocketAddress;
-import android.system.Os;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.io.IoUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetlinkSocketTest {
-    private final String TAG = "NetlinkSocketTest";
-
-    @Test
-    public void testBasicWorkingGetNeighborsQuery() throws Exception {
-        final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
-        assertNotNull(fd);
-
-        NetlinkSocket.connectToKernel(fd);
-
-        final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
-        assertNotNull(localAddr);
-        assertEquals(0, localAddr.getGroupsMask());
-        assertTrue(0 != localAddr.getPortId());
-
-        final int TEST_SEQNO = 5;
-        final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
-        assertNotNull(req);
-
-        final long TIMEOUT = 500;
-        assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
-
-        int neighMessageCount = 0;
-        int doneMessageCount = 0;
-
-        while (doneMessageCount == 0) {
-            ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
-            assertNotNull(response);
-            assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
-            assertEquals(0, response.position());
-            assertEquals(ByteOrder.nativeOrder(), response.order());
-
-            // Verify the messages at least appears minimally reasonable.
-            while (response.remaining() > 0) {
-                final NetlinkMessage msg = NetlinkMessage.parse(response);
-                assertNotNull(msg);
-                final StructNlMsgHdr hdr = msg.getHeader();
-                assertNotNull(hdr);
-
-                if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
-                    doneMessageCount++;
-                    continue;
-                }
-
-                assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-                assertTrue(msg instanceof RtNetlinkNeighborMessage);
-                assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0);
-                assertEquals(TEST_SEQNO, hdr.nlmsg_seq);
-                assertEquals(localAddr.getPortId(), hdr.nlmsg_pid);
-
-                neighMessageCount++;
-            }
-        }
-
-        assertEquals(1, doneMessageCount);
-        // TODO: make sure this test passes sanely in airplane mode.
-        assertTrue(neighMessageCount > 0);
-
-        IoUtils.closeQuietly(fd);
-    }
-}
diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
deleted file mode 100644
index 8162522..0000000
--- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.netlink;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlMsgHdr;
-import android.system.OsConstants;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RtNetlinkNeighborMessageTest {
-    private final String TAG = "RtNetlinkNeighborMessageTest";
-
-    // Hexadecimal representation of packet capture.
-    public static final String RTM_DELNEIGH_HEX =
-            // struct nlmsghdr
-            "4c000000" +     // length = 76
-            "1d00" +         // type = 29 (RTM_DELNEIGH)
-            "0000" +         // flags
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct ndmsg
-            "02" +           // family
-            "00" +           // pad1
-            "0000" +         // pad2
-            "15000000" +     // interface index (21  == wlan0, on test device)
-            "0400" +         // NUD state (0x04 == NUD_STALE)
-            "00" +           // flags
-            "01" +           // type
-            // struct nlattr: NDA_DST
-            "0800" +         // length = 8
-            "0100" +         // type (1 == NDA_DST, for neighbor messages)
-            "c0a89ffe" +     // IPv4 address (== 192.168.159.254)
-            // struct nlattr: NDA_LLADDR
-            "0a00" +         // length = 10
-            "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
-            "00005e000164" + // MAC Address (== 00:00:5e:00:01:64)
-            "0000" +         // padding, for 4 byte alignment
-            // struct nlattr: NDA_PROBES
-            "0800" +         // length = 8
-            "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
-            "01000000" +     // number of probes
-            // struct nlattr: NDA_CACHEINFO
-            "1400" +         // length = 20
-            "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
-            "05190000" +     // ndm_used, as "clock ticks ago"
-            "05190000" +     // ndm_confirmed, as "clock ticks ago"
-            "190d0000" +     // ndm_updated, as "clock ticks ago"
-            "00000000";      // ndm_refcnt
-    public static final byte[] RTM_DELNEIGH =
-            HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false);
-
-    // Hexadecimal representation of packet capture.
-    public static final String RTM_NEWNEIGH_HEX =
-            // struct nlmsghdr
-            "58000000" +     // length = 88
-            "1c00" +         // type = 28 (RTM_NEWNEIGH)
-            "0000" +         // flags
-            "00000000" +     // seqno
-            "00000000" +     // pid (0 == kernel)
-            // struct ndmsg
-            "0a" +           // family
-            "00" +           // pad1
-            "0000" +         // pad2
-            "15000000" +     // interface index (21  == wlan0, on test device)
-            "0400" +         // NUD state (0x04 == NUD_STALE)
-            "80" +           // flags
-            "01" +           // type
-            // struct nlattr: NDA_DST
-            "1400" +         // length = 20
-            "0100" +         // type (1 == NDA_DST, for neighbor messages)
-            "fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b)
-            // struct nlattr: NDA_LLADDR
-            "0a00" +         // length = 10
-            "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
-            "84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b)
-            "0000" +         // padding, for 4 byte alignment
-            // struct nlattr: NDA_PROBES
-            "0800" +         // length = 8
-            "0400" +         // type (4 == NDA_PROBES, for neighbor messages)
-            "01000000" +     // number of probes
-            // struct nlattr: NDA_CACHEINFO
-            "1400" +         // length = 20
-            "0300" +         // type (3 == NDA_CACHEINFO, for neighbor messages)
-            "eb0e0000" +     // ndm_used, as "clock ticks ago"
-            "861f0000" +     // ndm_confirmed, as "clock ticks ago"
-            "00000000" +     // ndm_updated, as "clock ticks ago"
-            "05000000";      // ndm_refcnt
-    public static final byte[] RTM_NEWNEIGH =
-            HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false);
-
-    // An example of the full response from an RTM_GETNEIGH query.
-    private static final String RTM_GETNEIGH_RESPONSE_HEX =
-            // <-- struct nlmsghr             -->|<-- struct ndmsg           -->|<-- struct nlattr: NDA_DST             -->|<-- NDA_LLADDR          -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO                         -->|
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" +
-            "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" +
-            "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000                         0400 0200                   0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000";
-    public static final byte[] RTM_GETNEIGH_RESPONSE =
-            HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false);
-
-    @Test
-    public void testParseRtmDelNeigh() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
-        assertNotNull(msg);
-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-        final StructNlMsgHdr hdr = neighMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(76, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
-        assertNotNull(ndmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family);
-        assertEquals(21, ndmsgHdr.ndm_ifindex);
-        assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
-        final InetAddress destination = neighMsg.getDestination();
-        assertNotNull(destination);
-        assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination);
-    }
-
-    @Test
-    public void testParseRtmNewNeigh() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
-        assertNotNull(msg);
-        assertTrue(msg instanceof RtNetlinkNeighborMessage);
-        final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-        final StructNlMsgHdr hdr = neighMsg.getHeader();
-        assertNotNull(hdr);
-        assertEquals(88, hdr.nlmsg_len);
-        assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-        assertEquals(0, hdr.nlmsg_flags);
-        assertEquals(0, hdr.nlmsg_seq);
-        assertEquals(0, hdr.nlmsg_pid);
-
-        final StructNdMsg ndmsgHdr = neighMsg.getNdHeader();
-        assertNotNull(ndmsgHdr);
-        assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family);
-        assertEquals(21, ndmsgHdr.ndm_ifindex);
-        assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state);
-        final InetAddress destination = neighMsg.getDestination();
-        assertNotNull(destination);
-        assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination);
-    }
-
-    @Test
-    public void testParseRtmGetNeighResponse() {
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE);
-        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
-
-        int messageCount = 0;
-        while (byteBuffer.remaining() > 0) {
-            final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
-            assertNotNull(msg);
-            assertTrue(msg instanceof RtNetlinkNeighborMessage);
-            final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg;
-
-            final StructNlMsgHdr hdr = neighMsg.getHeader();
-            assertNotNull(hdr);
-            assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type);
-            assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
-            assertEquals(0, hdr.nlmsg_seq);
-            assertEquals(11070, hdr.nlmsg_pid);
-
-            messageCount++;
-        }
-        // TODO: add more detailed spot checks.
-        assertEquals(14, messageCount);
-    }
-
-    @Test
-    public void testCreateRtmNewNeighMessage() {
-        final int seqNo = 2635;
-        final int ifIndex = 14;
-        final byte[] llAddr =
-                new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 };
-
-        // Hexadecimal representation of our created packet.
-        final String expectedNewNeighHex =
-                // struct nlmsghdr
-                "30000000" +     // length = 48
-                "1c00" +         // type = 28 (RTM_NEWNEIGH)
-                "0501" +         // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
-                "4b0a0000" +     // seqno
-                "00000000" +     // pid (0 == kernel)
-                // struct ndmsg
-                "02" +           // family
-                "00" +           // pad1
-                "0000" +         // pad2
-                "0e000000" +     // interface index (14)
-                "0800" +         // NUD state (0x08 == NUD_DELAY)
-                "00" +           // flags
-                "00" +           // type
-                // struct nlattr: NDA_DST
-                "0800" +         // length = 8
-                "0100" +         // type (1 == NDA_DST, for neighbor messages)
-                "7f000001" +     // IPv4 address (== 127.0.0.1)
-                // struct nlattr: NDA_LLADDR
-                "0a00" +         // length = 10
-                "0200" +         // type (2 == NDA_LLADDR, for neighbor messages)
-                "010203040506" + // MAC Address (== 01:02:03:04:05:06)
-                "0000";          // padding, for 4 byte alignment
-        final byte[] expectedNewNeigh =
-                HexEncoding.decode(expectedNewNeighHex.toCharArray(), false);
-
-        final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage(
-            seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr);
-        if (!Arrays.equals(expectedNewNeigh, bytes)) {
-            assertEquals(expectedNewNeigh.length, bytes.length);
-            for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) {
-                assertEquals(expectedNewNeigh[i], bytes[i]);
-            }
-        }
-    }
-}
diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
deleted file mode 100644
index 35f8c79..0000000
--- a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
-import static android.net.shared.Inet4AddressUtils.getImplicitNetmask;
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL;
-import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength;
-import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.fail;
-
-import android.net.InetAddresses;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class Inet4AddressUtilsTest {
-
-    @Test
-    public void testInet4AddressToIntHTL() {
-        assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0")));
-        assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0")));
-        assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0")));
-        assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0")));
-        assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254")));
-        assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255")));
-    }
-
-    @Test
-    public void testIntToInet4AddressHTL() {
-        assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0));
-        assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
-        assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
-        assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
-        assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
-        assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
-    }
-
-    @Test
-    public void testInet4AddressToIntHTH() {
-        assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0")));
-        assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0")));
-        assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0")));
-        assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0")));
-        assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254")));
-        assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255")));
-    }
-
-    @Test
-    public void testIntToInet4AddressHTH() {
-        assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0));
-        assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
-        assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
-        assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
-        assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
-        assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
-    }
-
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTL() {
-        assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
-        assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
-        assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
-        assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
-        assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
-        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
-    }
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTH() {
-        assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
-        assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
-        assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
-        assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
-        assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
-        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
-        prefixLengthToV4NetmaskIntHTH(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
-        prefixLengthToV4NetmaskIntHTH(33);
-    }
-
-    private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
-        final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
-        final int addrInt = inet4AddressToIntHTH(ipv4Address(addr));
-        assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
-    }
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
-        checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
-        checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
-        checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
-        checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
-    }
-
-    @Test
-    public void testGetImplicitNetmask() {
-        assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2")));
-        assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7")));
-        assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105")));
-        assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145")));
-        assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1")));
-        assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1")));
-        assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1")));
-        assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8")));
-    }
-
-    private void assertInvalidNetworkMask(Inet4Address addr) {
-        try {
-            netmaskToPrefixLength(addr);
-            fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testNetmaskToPrefixLength() {
-        assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0")));
-        assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0")));
-        assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0")));
-        assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0")));
-        assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254")));
-        assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255")));
-
-        assertInvalidNetworkMask(ipv4Address("0.0.0.1"));
-        assertInvalidNetworkMask(ipv4Address("255.255.255.253"));
-        assertInvalidNetworkMask(ipv4Address("255.255.0.255"));
-    }
-
-    @Test
-    public void testGetPrefixMaskAsAddress() {
-        assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
-        assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
-        assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
-        assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
-    }
-
-    @Test
-    public void testGetBroadcastAddress() {
-        assertEquals("192.168.15.255",
-                getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress());
-        assertEquals("192.255.255.255",
-                getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress());
-        assertEquals("192.168.0.123",
-                getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress());
-        assertEquals("255.255.255.255",
-                getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetBroadcastAddress_PrefixTooLarge() {
-        getBroadcastAddress(ipv4Address("192.168.0.123"), 33);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetBroadcastAddress_NegativePrefix() {
-        getBroadcastAddress(ipv4Address("192.168.0.123"), -1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
-        getPrefixMaskAsInet4Address(33);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetPrefixMaskAsAddress_NegativePrefix() {
-        getPrefixMaskAsInet4Address(-1);
-    }
-
-    private Inet4Address ipv4Address(String addr) {
-        return (Inet4Address) InetAddresses.parseNumericAddress(addr);
-    }
-}
diff --git a/tests/net/java/android/net/shared/InitialConfigurationTest.java b/tests/net/java/android/net/shared/InitialConfigurationTest.java
deleted file mode 100644
index 17f8324..0000000
--- a/tests/net/java/android/net/shared/InitialConfigurationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
-
-/**
- * Tests for {@link InitialConfiguration}
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InitialConfigurationTest {
-    private InitialConfiguration mConfig;
-
-    @Before
-    public void setUp() {
-        mConfig = new InitialConfiguration();
-        mConfig.ipAddresses.addAll(Arrays.asList(
-                new LinkAddress(parseNumericAddress("192.168.45.45"), 16),
-                new LinkAddress(parseNumericAddress("2001:db8::45"), 33)));
-        mConfig.directlyConnectedRoutes.addAll(Arrays.asList(
-                new IpPrefix(parseNumericAddress("192.168.46.46"), 17),
-                new IpPrefix(parseNumericAddress("2001:db8::46"), 34)));
-        mConfig.dnsServers.addAll(Arrays.asList(
-                parseNumericAddress("192.168.47.47"),
-                parseNumericAddress("2001:db8::47")));
-        // Any added InitialConfiguration field must be included in equals() to be tested properly
-        assertFieldCountEquals(3, InitialConfiguration.class);
-    }
-
-    @Test
-    public void testParcelUnparcelInitialConfiguration() {
-        final InitialConfiguration unparceled =
-                InitialConfiguration.fromStableParcelable(mConfig.toStableParcelable());
-        assertEquals(mConfig, unparceled);
-    }
-
-    @Test
-    public void testEquals() {
-        assertEquals(mConfig, InitialConfiguration.copy(mConfig));
-
-        assertNotEqualsAfterChange(c -> c.ipAddresses.add(
-                new LinkAddress(parseNumericAddress("192.168.47.47"), 24)));
-        assertNotEqualsAfterChange(c -> c.directlyConnectedRoutes.add(
-                new IpPrefix(parseNumericAddress("192.168.46.46"), 32)));
-        assertNotEqualsAfterChange(c -> c.dnsServers.add(parseNumericAddress("2001:db8::49")));
-        assertFieldCountEquals(3, InitialConfiguration.class);
-    }
-
-    private void assertNotEqualsAfterChange(Consumer<InitialConfiguration> mutator) {
-        final InitialConfiguration newConfig = InitialConfiguration.copy(mConfig);
-        mutator.accept(newConfig);
-        assertNotEquals(mConfig, newConfig);
-    }
-}
diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
deleted file mode 100644
index f987389..0000000
--- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
-import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-
-/**
- * Tests for {@link IpConfigurationParcelableUtil}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConfigurationParcelableUtilTest {
-    private DhcpResults mDhcpResults;
-
-    @Before
-    public void setUp() {
-        mDhcpResults = new DhcpResults();
-        mDhcpResults.ipAddress = new LinkAddress(parseNumericAddress("2001:db8::42"), 64);
-        mDhcpResults.gateway = parseNumericAddress("192.168.42.42");
-        mDhcpResults.dnsServers.add(parseNumericAddress("2001:db8::43"));
-        mDhcpResults.dnsServers.add(parseNumericAddress("192.168.43.43"));
-        mDhcpResults.domains = "example.com";
-        mDhcpResults.serverAddress = (Inet4Address) parseNumericAddress("192.168.44.44");
-        mDhcpResults.vendorInfo = "TEST_VENDOR_INFO";
-        mDhcpResults.leaseDuration = 3600;
-        mDhcpResults.serverHostName = "dhcp.example.com";
-        mDhcpResults.mtu = 1450;
-        // Any added DhcpResults field must be included in equals() to be tested properly
-        assertFieldCountEquals(9, DhcpResults.class);
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults() {
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullIpAddress() {
-        mDhcpResults.ipAddress = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullGateway() {
-        mDhcpResults.gateway = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullDomains() {
-        mDhcpResults.domains = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_EmptyDomains() {
-        mDhcpResults.domains = "";
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullServerAddress() {
-        mDhcpResults.serverAddress = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullVendorInfo() {
-        mDhcpResults.vendorInfo = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcelDhcpResults_NullServerHostName() {
-        mDhcpResults.serverHostName = null;
-        doDhcpResultsParcelUnparcelTest();
-    }
-
-    private void doDhcpResultsParcelUnparcelTest() {
-        final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults));
-        assertEquals(mDhcpResults, unparceled);
-    }
-}
diff --git a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java b/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
deleted file mode 100644
index 7079a28..0000000
--- a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.shared;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.shared.ProvisioningConfiguration.fromStableParcelable;
-
-import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.StaticIpConfiguration;
-import android.net.apf.ApfCapabilities;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.Consumer;
-
-/**
- * Tests for {@link ProvisioningConfiguration}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ProvisioningConfigurationTest {
-    private ProvisioningConfiguration mConfig;
-
-    @Before
-    public void setUp() {
-        mConfig = new ProvisioningConfiguration();
-        mConfig.mEnableIPv4 = true;
-        mConfig.mEnableIPv6 = true;
-        mConfig.mUsingMultinetworkPolicyTracker = true;
-        mConfig.mUsingIpReachabilityMonitor = true;
-        mConfig.mRequestedPreDhcpActionMs = 42;
-        mConfig.mInitialConfig = new InitialConfiguration();
-        mConfig.mInitialConfig.ipAddresses.add(
-                new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
-        mConfig.mStaticIpConfig = new StaticIpConfiguration();
-        mConfig.mStaticIpConfig.ipAddress =
-                new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
-        // Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests
-        mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3);
-        mConfig.mProvisioningTimeoutMs = 4200;
-        mConfig.mIPv6AddrGenMode = 123;
-        mConfig.mNetwork = new Network(321);
-        mConfig.mDisplayName = "test_config";
-        // Any added field must be included in equals() to be tested properly
-        assertFieldCountEquals(12, ProvisioningConfiguration.class);
-    }
-
-    @Test
-    public void testParcelUnparcel() {
-        doParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcel_NullInitialConfiguration() {
-        mConfig.mInitialConfig = null;
-        doParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcel_NullStaticConfiguration() {
-        mConfig.mStaticIpConfig = null;
-        doParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcel_NullApfCapabilities() {
-        mConfig.mApfCapabilities = null;
-        doParcelUnparcelTest();
-    }
-
-    @Test
-    public void testParcelUnparcel_NullNetwork() {
-        mConfig.mNetwork = null;
-        doParcelUnparcelTest();
-    }
-
-    private void doParcelUnparcelTest() {
-        final ProvisioningConfiguration unparceled =
-                fromStableParcelable(mConfig.toStableParcelable());
-        assertEquals(mConfig, unparceled);
-    }
-
-    @Test
-    public void testEquals() {
-        assertEquals(mConfig, new ProvisioningConfiguration(mConfig));
-
-        assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false);
-        assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false);
-        assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false);
-        assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false);
-        assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++);
-        assertNotEqualsAfterChange(c -> c.mInitialConfig.ipAddresses.add(
-                new LinkAddress(parseNumericAddress("192.168.47.47"), 16)));
-        assertNotEqualsAfterChange(c -> c.mInitialConfig = null);
-        assertNotEqualsAfterChange(c -> c.mStaticIpConfig.ipAddress =
-                new LinkAddress(parseNumericAddress("2001:db8::47"), 64));
-        assertNotEqualsAfterChange(c -> c.mStaticIpConfig = null);
-        assertNotEqualsAfterChange(c -> c.mApfCapabilities = new ApfCapabilities(4, 5, 6));
-        assertNotEqualsAfterChange(c -> c.mApfCapabilities = null);
-        assertNotEqualsAfterChange(c -> c.mProvisioningTimeoutMs++);
-        assertNotEqualsAfterChange(c -> c.mIPv6AddrGenMode++);
-        assertNotEqualsAfterChange(c -> c.mNetwork = new Network(123));
-        assertNotEqualsAfterChange(c -> c.mNetwork = null);
-        assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
-        assertNotEqualsAfterChange(c -> c.mDisplayName = null);
-        assertFieldCountEquals(12, ProvisioningConfiguration.class);
-    }
-
-    private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {
-        final ProvisioningConfiguration newConfig = new ProvisioningConfiguration(mConfig);
-        mutator.accept(newConfig);
-        assertNotEquals(mConfig, newConfig);
-    }
-}
diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java
deleted file mode 100644
index 141455c..0000000
--- a/tests/net/java/android/net/util/InterfaceParamsTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class InterfaceParamsTest {
-    @Test
-    public void testNullInterfaceReturnsNull() {
-        assertNull(InterfaceParams.getByName(null));
-    }
-
-    @Test
-    public void testNonExistentInterfaceReturnsNull() {
-        assertNull(InterfaceParams.getByName("doesnotexist0"));
-    }
-
-    @Test
-    public void testLoopback() {
-        final InterfaceParams ifParams = InterfaceParams.getByName("lo");
-        assertNotNull(ifParams);
-        assertEquals("lo", ifParams.name);
-        assertTrue(ifParams.index > 0);
-        assertNotNull(ifParams.macAddr);
-        assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU);
-    }
-}
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
deleted file mode 100644
index e1dba36..0000000
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SharedLogTest {
-    private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
-    private static final String TIMESTAMP = "HH:MM:SS";
-
-    @Test
-    public void testBasicOperation() {
-        final SharedLog logTop = new SharedLog("top");
-        logTop.mark("first post!");
-
-        final SharedLog logLevel2a = logTop.forSubComponent("twoA");
-        final SharedLog logLevel2b = logTop.forSubComponent("twoB");
-        logLevel2b.e("2b or not 2b");
-        logLevel2b.e("No exception", null);
-        logLevel2b.e("Wait, here's one", new Exception("Test"));
-        logLevel2a.w("second post?");
-
-        final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
-        logTop.log("still logging");
-        logLevel3.log("3 >> 2");
-        logLevel2a.mark("ok: last post");
-
-        final String[] expected = {
-            " - MARK first post!",
-            " - [twoB] ERROR 2b or not 2b",
-            " - [twoB] ERROR No exception",
-            // No stacktrace in shared log, only in logcat
-            " - [twoB] ERROR Wait, here's one: Test",
-            " - [twoA] WARN second post?",
-            " - still logging",
-            " - [twoA.three] 3 >> 2",
-            " - [twoA] MARK ok: last post",
-        };
-        // Verify the logs are all there and in the correct order.
-        verifyLogLines(expected, logTop);
-
-        // In fact, because they all share the same underlying LocalLog,
-        // every subcomponent SharedLog's dump() is identical.
-        verifyLogLines(expected, logLevel2a);
-        verifyLogLines(expected, logLevel2b);
-        verifyLogLines(expected, logLevel3);
-    }
-
-    private static void verifyLogLines(String[] expected, SharedLog log) {
-        final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
-        final PrintWriter pw = new PrintWriter(ostream, true);
-        log.dump(null, pw, null);
-
-        final String dumpOutput = ostream.toString();
-        assertTrue(dumpOutput != null);
-        assertTrue(!"".equals(dumpOutput));
-
-        final String[] lines = dumpOutput.split("\n");
-        assertEquals(expected.length, lines.length);
-
-        for (int i = 0; i < expected.length; i++) {
-            String got = lines[i];
-            String want = expected[i];
-            assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
-            assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
-                    got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
-        }
-    }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1d2e6b0..7ea9bcf 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,6 +23,9 @@
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
 import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -31,6 +34,7 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
@@ -148,6 +152,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
+import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
@@ -247,6 +252,7 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
 
 import kotlin.reflect.KClass;
 
@@ -333,6 +339,9 @@
 
     private class MockContext extends BroadcastInterceptingContext {
         private final MockContentResolver mContentResolver;
+        // Contains all registered receivers since this object was created. Useful to clear
+        // them when needed, as BroadcastInterceptingContext does not provide this facility.
+        private final List<BroadcastReceiver> mRegisteredReceivers = new ArrayList<>();
 
         @Spy private Resources mResources;
         private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
@@ -346,6 +355,7 @@
                             "wifi,1,1,1,-1,true",
                             "mobile,0,0,0,-1,true",
                             "mobile_mms,2,0,2,60000,true",
+                            "mobile_supl,3,0,2,60000,true",
                     });
 
             when(mResources.getStringArray(
@@ -413,6 +423,19 @@
             // make sure the code does not rely on unexpected permissions.
             super.enforceCallingOrSelfPermission(permission, message);
         }
+
+        @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+            mRegisteredReceivers.add(receiver);
+            return super.registerReceiver(receiver, filter);
+        }
+
+        public void clearRegisteredReceivers() {
+            // super.unregisterReceiver is a no-op for receivers that are not registered (because
+            // they haven't been registered or because they have already been unregistered).
+            // For the same reason, don't bother clearing mRegisteredReceivers.
+            for (final BroadcastReceiver rcv : mRegisteredReceivers) unregisterReceiver(rcv);
+        }
     }
 
     private void waitForIdle() {
@@ -441,7 +464,7 @@
         }
 
         // Bring up a network that we can use to send messages to ConnectivityService.
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -461,7 +484,7 @@
     @Ignore
     public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
         // Bring up a network that we can use to send messages to ConnectivityService.
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
@@ -1230,17 +1253,26 @@
      * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
      * broadcasts are received.
      */
-    private ConditionVariable waitForConnectivityBroadcasts(final int count) {
+    private ConditionVariable registerConnectivityBroadcast(final int count) {
+        return registerConnectivityBroadcastThat(count, intent -> true);
+    }
+
+    private ConditionVariable registerConnectivityBroadcastThat(final int count,
+            @NonNull final Predicate<Intent> filter) {
         final ConditionVariable cv = new ConditionVariable();
-        mServiceContext.registerReceiver(new BroadcastReceiver() {
+        final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
+        intentFilter.addAction(CONNECTIVITY_ACTION_SUPL);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
                     private int remaining = count;
                     public void onReceive(Context context, Intent intent) {
+                        if (!filter.test(intent)) return;
                         if (--remaining == 0) {
                             cv.open();
                             mServiceContext.unregisterReceiver(this);
                         }
                     }
-                }, new IntentFilter(CONNECTIVITY_ACTION));
+                };
+        mServiceContext.registerReceiver(receiver, intentFilter);
         return cv;
     }
 
@@ -1261,6 +1293,75 @@
     }
 
     @Test
+    public void testNetworkFeature() throws Exception {
+        // Connect the cell agent and wait for the connected broadcast.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
+        final ConditionVariable cv1 = registerConnectivityBroadcastThat(1,
+                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE);
+        mCellNetworkAgent.connect(true);
+        waitFor(cv1);
+
+        // Build legacy request for SUPL.
+        final NetworkCapabilities legacyCaps = new NetworkCapabilities();
+        legacyCaps.addTransportType(TRANSPORT_CELLULAR);
+        legacyCaps.addCapability(NET_CAPABILITY_SUPL);
+        final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
+                ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
+
+        // Send request and check that the legacy broadcast for SUPL is sent correctly.
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        final ConditionVariable cv2 = registerConnectivityBroadcastThat(1,
+                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+        mCm.requestNetwork(legacyRequest, callback);
+        callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+        waitFor(cv2);
+
+        // File another request, withdraw it and make sure no broadcast is sent
+        final ConditionVariable cv3 = registerConnectivityBroadcast(1);
+        final TestNetworkCallback callback2 = new TestNetworkCallback();
+        mCm.requestNetwork(legacyRequest, callback2);
+        callback2.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+        mCm.unregisterNetworkCallback(callback2);
+        assertFalse(cv3.block(800)); // 800ms long enough to at least flake if this is sent
+        // As the broadcast did not fire, the receiver was not unregistered. Do this now.
+        mServiceContext.clearRegisteredReceivers();
+
+        // Withdraw the request and check that the broadcast for disconnection is sent.
+        final ConditionVariable cv4 = registerConnectivityBroadcastThat(1, intent ->
+                !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected()
+                        && intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+        mCm.unregisterNetworkCallback(callback);
+        waitFor(cv4);
+
+        // Re-file the request and expect the connected broadcast again
+        final ConditionVariable cv5 = registerConnectivityBroadcastThat(1,
+                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
+        final TestNetworkCallback callback3 = new TestNetworkCallback();
+        mCm.requestNetwork(legacyRequest, callback3);
+        callback3.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+        waitFor(cv5);
+
+        // Disconnect the network and expect two disconnected broadcasts, one for SUPL and one
+        // for mobile. Use a small hack to check that both have been sent, but the order is
+        // not contractual.
+        final AtomicBoolean vanillaAction = new AtomicBoolean(false);
+        final AtomicBoolean suplAction = new AtomicBoolean(false);
+        final ConditionVariable cv6 = registerConnectivityBroadcastThat(2, intent -> {
+            if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
+                vanillaAction.set(true);
+            } else if (intent.getAction().equals(CONNECTIVITY_ACTION_SUPL)) {
+                suplAction.set(true);
+            }
+            return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
+        });
+        mCellNetworkAgent.disconnect();
+        waitFor(cv6);
+        assertTrue(vanillaAction.get());
+        assertTrue(suplAction.get());
+    }
+
+    @Test
     public void testLingering() throws Exception {
         verifyNoNetwork();
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -1268,7 +1369,7 @@
         assertNull(mCm.getActiveNetworkInfo());
         assertNull(mCm.getActiveNetwork());
         // Test bringing up validated cellular.
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
@@ -1278,7 +1379,7 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
         // Test bringing up validated WiFi.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1295,7 +1396,7 @@
         assertLength(1, mCm.getAllNetworks());
         assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
         // Test WiFi disconnect.
-        cv = waitForConnectivityBroadcasts(1);
+        cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.disconnect();
         waitFor(cv);
         verifyNoNetwork();
@@ -1305,7 +1406,7 @@
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1320,17 +1421,17 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test cellular disconnect.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mCellNetworkAgent.disconnect();
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi disconnect.
-        cv = waitForConnectivityBroadcasts(1);
+        cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.disconnect();
         waitFor(cv);
         verifyNoNetwork();
@@ -1340,23 +1441,23 @@
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi disconnect.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.disconnect();
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test cellular disconnect.
-        cv = waitForConnectivityBroadcasts(1);
+        cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.disconnect();
         waitFor(cv);
         verifyNoNetwork();
@@ -1366,7 +1467,7 @@
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1374,14 +1475,14 @@
                 NET_CAPABILITY_VALIDATED));
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         // Test cellular disconnect.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mCellNetworkAgent.disconnect();
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1394,23 +1495,23 @@
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi getting really weak.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.adjustScore(-11);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test WiFi restoring signal strength.
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.adjustScore(11);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1430,7 +1531,7 @@
         mCellNetworkAgent.expectDisconnected();
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        final ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1449,18 +1550,18 @@
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Reevaluate WiFi (it'll instantly fail DNS).
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
@@ -1470,7 +1571,7 @@
                 NET_CAPABILITY_VALIDATED));
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Reevaluate cellular (it'll instantly fail DNS).
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
@@ -1487,18 +1588,18 @@
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Reevaluate cellular (it'll instantly fail DNS).
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
@@ -1573,7 +1674,7 @@
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
 
         // Test unvalidated networks
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1588,7 +1689,7 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1597,7 +1698,7 @@
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
-        cv = waitForConnectivityBroadcasts(2);
+        cv = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.disconnect();
         genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -1605,7 +1706,7 @@
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
-        cv = waitForConnectivityBroadcasts(1);
+        cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.disconnect();
         genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -2203,7 +2304,7 @@
 
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        final ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        final ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -2231,7 +2332,7 @@
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
@@ -3692,7 +3793,7 @@
         }
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -4225,7 +4326,7 @@
         assertNotPinnedToWifi();
 
         // Disconnect cell and wifi.
-        ConditionVariable cv = waitForConnectivityBroadcasts(3);  // cell down, wifi up, wifi down.
+        ConditionVariable cv = registerConnectivityBroadcast(3);  // cell down, wifi up, wifi down.
         mCellNetworkAgent.disconnect();
         mWiFiNetworkAgent.disconnect();
         waitFor(cv);
@@ -4238,7 +4339,7 @@
         assertPinnedToWifiWithWifiDefault();
 
         // ... and is maintained even when that network is no longer the default.
-        cv = waitForConnectivityBroadcasts(1);
+        cv = registerConnectivityBroadcast(1);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connect(true);
         waitFor(cv);
@@ -4339,7 +4440,7 @@
 
     @Test
     public void testNetworkInfoOfTypeNone() throws Exception {
-        ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
+        ConditionVariable broadcastCV = registerConnectivityBroadcast(1);
 
         verifyNoNetwork();
         TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
@@ -5791,7 +5892,7 @@
                 .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        ConditionVariable cv = registerConnectivityBroadcast(1);
         reset(mNetworkManagementService);
         mWiFiNetworkAgent.disconnect();
         waitFor(cv);
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index f045369..42d4cf3 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -18,6 +18,7 @@
 
 import android.net.ConnectivityManager.TYPE_ETHERNET
 import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
 import android.net.ConnectivityManager.TYPE_WIFI
 import android.net.ConnectivityManager.TYPE_WIMAX
 import android.net.NetworkInfo.DetailedState.CONNECTED
@@ -46,7 +47,7 @@
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class LegacyTypeTrackerTest {
-    private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET)
+    private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
 
     private val mMockService = mock(ConnectivityService::class.java).apply {
         doReturn(false).`when`(this).isDefaultNetwork(any())
@@ -70,6 +71,26 @@
     }
 
     @Test
+    fun testSupl() {
+        val mobileNai = mock(NetworkAgentInfo::class.java)
+        mTracker.add(TYPE_MOBILE, mobileNai)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
+        reset(mMockService)
+        mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
+        reset(mMockService)
+        mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
+        reset(mMockService)
+        mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
+        reset(mMockService)
+        mTracker.remove(mobileNai, false)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
+        verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
+    }
+
+    @Test
     fun testAddNetwork() {
         val mobileNai = mock(NetworkAgentInfo::class.java)
         val wifiNai = mock(NetworkAgentInfo::class.java)
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 9580763..d57f225 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -40,6 +41,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
 import org.junit.Before;
@@ -60,12 +62,19 @@
 
     static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
     static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
+    static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
     static {
         CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
         CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+
+        // Set the underyling network to wifi.
+        VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+        VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
+        VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
     }
 
     @Mock Context mCtx;
@@ -75,6 +84,7 @@
     @Mock NotificationManager mNotificationManager;
     @Mock NetworkAgentInfo mWifiNai;
     @Mock NetworkAgentInfo mCellNai;
+    @Mock NetworkAgentInfo mVpnNai;
     @Mock NetworkInfo mNetworkInfo;
     ArgumentCaptor<Notification> mCaptor;
 
@@ -88,6 +98,9 @@
         mWifiNai.networkInfo = mNetworkInfo;
         mCellNai.networkCapabilities = CELL_CAPABILITIES;
         mCellNai.networkInfo = mNetworkInfo;
+        mVpnNai.networkCapabilities = VPN_CAPABILITIES;
+        mVpnNai.networkInfo = mNetworkInfo;
+        doReturn(true).when(mVpnNai).isVPN();
         when(mCtx.getResources()).thenReturn(mResources);
         when(mCtx.getPackageManager()).thenReturn(mPm);
         when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -97,6 +110,35 @@
         mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
     }
 
+    private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
+        final String tag = NetworkNotificationManager.tagFor(id);
+        mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
+        verify(mNotificationManager, times(1))
+                .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
+        final int transportType = NetworkNotificationManager.approximateTransportType(nai);
+        if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
+            verify(mResources, times(1)).getString(title, eq(any()));
+        } else {
+            verify(mResources, times(1)).getString(title);
+        }
+        verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+    }
+
+    @Test
+    public void testTitleOfPrivateDnsBroken() {
+        // Test the title of mobile data.
+        verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
+        reset(mResources);
+
+        // Test the title of wifi.
+        verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
+        reset(mResources);
+
+        // Test the title of other networks.
+        verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
+        reset(mResources);
+    }
+
     @Test
     public void testNotificationsShownAndCleared() {
         final int NETWORK_ID_BASE = 100;
diff --git a/tools/genprotos.sh b/tools/genprotos.sh
deleted file mode 100755
index f901c9f..0000000
--- a/tools/genprotos.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-# TODO This should not be needed. If you set a custom OUT_DIR or OUT_DIR_COMMON_BASE you can
-# end up with a command that is extremely long, potentially going passed MAX_ARG_STRLEN due to
-# the way sbox rewrites the command. See b/70221552.
-
-set -e
-
-location_aprotoc=$1
-location_protoc=$2
-location_soong_zip=$3
-genDir=$4
-depfile=$5
-in=$6
-out=$7
-
-mkdir -p ${genDir}/${in} && \
-  ${location_aprotoc} --plugin=${location_protoc} \
-                      --dependency_out=${depfile} \
-                      --javastream_out=${genDir}/${in} \
-                      -Iexternal/protobuf/src \
-                      -I . \
-                      ${in} && \
-  ${location_soong_zip} -jar -o ${out} -C ${genDir}/${in} -D ${genDir}/${in}
diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp
index 0e33fdd..1e96234 100644
--- a/tools/processors/unsupportedappusage/Android.bp
+++ b/tools/processors/unsupportedappusage/Android.bp
@@ -1,11 +1,6 @@
 
-java_plugin {
-    name: "unsupportedappusage-annotation-processor",
-    processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
-
-    java_resources: [
-        "META-INF/**/*",
-    ],
+java_library_host {
+    name: "unsupportedappusage-annotation-processor-lib",
     srcs: [
         "src/**/*.java",
     ],
@@ -22,6 +17,18 @@
             "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
         ],
     },
+}
+
+java_plugin {
+    name: "unsupportedappusage-annotation-processor",
+    processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
+
+    java_resources: [
+        "META-INF/**/*",
+    ],
+    static_libs: [
+        "unsupportedappusage-annotation-processor-lib"
+    ],
 
     use_tools_jar: true,
 }
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
index 5a5703e..65fc733 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
+++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
@@ -101,14 +101,20 @@
     private String getClassSignature(TypeElement clazz) {
         StringBuilder sb = new StringBuilder("L");
         for (Element enclosing : getEnclosingElements(clazz)) {
-            if (enclosing.getKind() == PACKAGE) {
-                sb.append(((PackageElement) enclosing)
-                        .getQualifiedName()
-                        .toString()
-                        .replace('.', '/'));
-                sb.append('/');
-            } else {
-                sb.append(enclosing.getSimpleName()).append('$');
+            switch (enclosing.getKind()) {
+                case MODULE:
+                    // ignore this.
+                    break;
+                case PACKAGE:
+                    sb.append(((PackageElement) enclosing)
+                            .getQualifiedName()
+                            .toString()
+                            .replace('.', '/'));
+                    sb.append('/');
+                    break;
+                default:
+                    sb.append(enclosing.getSimpleName()).append('$');
+                    break;
             }
 
         }
diff --git a/tools/processors/unsupportedappusage/test/Android.bp b/tools/processors/unsupportedappusage/test/Android.bp
new file mode 100644
index 0000000..49ea3d4
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+    name: "unsupportedappusage-processor-test",
+
+    srcs: ["src/**/*.java"],
+
+    static_libs: [
+        "libjavac",
+        "unsupportedappusage-annotation-processor-lib",
+        "truth-host-prebuilt",
+        "mockito-host",
+        "junit-host",
+        "objenesis",
+    ],
+}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
new file mode 100644
index 0000000..23db99e
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor.unsupportedappusage;
+
+import com.google.common.base.Splitter;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CsvReader {
+
+    private final Splitter mSplitter;
+    private final List<String> mColumns;
+    private final List<Map<String, String>> mContents;
+
+    public CsvReader(InputStream in) throws IOException {
+        mSplitter = Splitter.on(",");
+        BufferedReader br = new BufferedReader(new InputStreamReader(in));
+        mColumns = mSplitter.splitToList(br.readLine());
+        mContents = new ArrayList<>();
+        String line = br.readLine();
+        while (line != null) {
+            List<String> contents = mSplitter.splitToList(line);
+            Map<String, String> contentMap = new HashMap<>();
+            for (int i = 0; i < Math.min(contents.size(), mColumns.size()); ++i) {
+                contentMap.put(mColumns.get(i), contents.get(i));
+            }
+            mContents.add(contentMap);
+            line = br.readLine();
+        }
+        br.close();
+    }
+
+    public List<String> getColumns() {
+        return mColumns;
+    }
+
+    public List<Map<String, String>> getContents() {
+        return mContents;
+    }
+}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
new file mode 100644
index 0000000..012e88f
--- /dev/null
+++ b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor.unsupportedappusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.javac.Javac;
+
+import com.google.common.base.Joiner;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class UnsupportedAppUsageProcessorTest {
+
+    private Javac mJavac;
+
+    @Before
+    public void setup() throws IOException {
+        mJavac = new Javac();
+        mJavac.addSource("dalvik.annotation.compat.UnsupportedAppUsage", Joiner.on('\n').join(
+                "package dalvik.annotation.compat;",
+                "public @interface UnsupportedAppUsage {",
+                "    String expectedSignature() default \"\";\n",
+                "    String someProperty() default \"\";",
+                "}"));
+    }
+
+    private CsvReader compileAndReadCsv() throws IOException {
+        mJavac.compileWithAnnotationProcessor(new UnsupportedAppUsageProcessor());
+        return new CsvReader(
+                mJavac.getOutputFile("unsupportedappusage/unsupportedappusage_index.csv"));
+    }
+
+    @Test
+    public void testSignatureFormat() throws Exception {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;",
+                "import dalvik.annotation.compat.UnsupportedAppUsage;",
+                "public class Class {",
+                "  @UnsupportedAppUsage",
+                "  public void method() {}",
+                "}"));
+        assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
+                "signature", "La/b/Class;->method()V"
+        );
+    }
+
+    @Test
+    public void testSourcePosition() throws Exception {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;", // 1
+                "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
+                "public class Class {", // 3
+                "  @UnsupportedAppUsage", // 4
+                "  public void method() {}", // 5
+                "}"));
+        Map<String, String> row = compileAndReadCsv().getContents().get(0);
+        assertThat(row).containsEntry("startline", "4");
+        assertThat(row).containsEntry("startcol", "3");
+        assertThat(row).containsEntry("endline", "4");
+        assertThat(row).containsEntry("endcol", "23");
+    }
+
+    @Test
+    public void testAnnotationProperties() throws Exception {
+        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+                "package a.b;", // 1
+                "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
+                "public class Class {", // 3
+                "  @UnsupportedAppUsage(someProperty=\"value\")", // 4
+                "  public void method() {}", // 5
+                "}"));
+        assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
+                "properties", "someProperty=%22value%22");
+    }
+
+
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 68355c6..b53b2aa 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1128,6 +1128,9 @@
      */
     private static final int MAX_ACTIVE_LOCKS = 50;
 
+    /** Indicates an invalid SSID. */
+    public static final String UNKNOWN_SSID = "<unknown ssid>";
+
     /* Number of currently active WifiLocks and MulticastLocks */
     @UnsupportedAppUsage
     private int mActiveLockCount;
@@ -2326,7 +2329,7 @@
      * <p>
      * In the connected state, access to the SSID and BSSID requires
      * the same permissions as {@link #getScanResults}. If such access is not allowed,
-     * {@link WifiInfo#getSSID} will return {@code "<unknown ssid>"} and
+     * {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
      * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
      *
      * @return the Wi-Fi information, contained in {@link WifiInfo}.
@@ -3117,7 +3120,7 @@
 
     /**
      * Base class for soft AP callback. Should be extended by applications and set when calling
-     * {@link WifiManager#registerSoftApCallback(SoftApCallback, Handler)}.
+     * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
      *
      * @hide
      */
@@ -3197,16 +3200,16 @@
      * without the permission will trigger a {@link java.lang.SecurityException}.
      * <p>
      *
-     * @param callback Callback for soft AP events
      * @param executor The executor to execute the callbacks of the {@code executor}
      *                 object. If null, then the application's main executor will be used.
+     * @param callback Callback for soft AP events
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void registerSoftApCallback(@NonNull SoftApCallback callback,
-                                       @Nullable @CallbackExecutor Executor executor) {
+    public void registerSoftApCallback(@Nullable @CallbackExecutor Executor executor,
+                                       @NonNull SoftApCallback callback) {
         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
 
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index b22ae070..5a212a8 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
 import android.net.ScoredNetwork;
 import android.os.Handler;
 import android.os.Process;
@@ -40,7 +41,8 @@
  *
  * @hide
  */
-public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
+        implements NetworkScoreManager.NetworkScoreCallback {
     private static final String TAG = "WifiNetworkScoreCache";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -246,6 +248,17 @@
     }
 
     @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults());
+    }
+
+    /**
+     * This is directly invoked from within Wifi-Service (on it's instance of this class), hence
+     * avoid making the WifiManager.getScanResults() call to avoid a deadlock.
+     */
+    public final void dumpWithLatestScanResults(
+            FileDescriptor fd, PrintWriter writer, String[] args,
+            List<ScanResult> latestScanResults) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
         String header = String.format("WifiNetworkScoreCache (%s/%d)",
                 mContext.getPackageName(), Process.myUid());
@@ -256,8 +269,7 @@
                 writer.println("    " + score);
             }
             writer.println("  Network scores for latest ScanResults:");
-            WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-            for (ScanResult scanResult : wifiManager.getScanResults()) {
+            for (ScanResult scanResult : latestScanResults) {
                 writer.println(
                         "    " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
             }
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index 70ca088..f187e10 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -48,7 +48,7 @@
 
     private static final int HEX_RADIX = 16;
     @UnsupportedAppUsage
-    public static final String NONE = "<unknown ssid>";
+    public static final String NONE = WifiManager.UNKNOWN_SSID;
 
     private WifiSsid() {
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index cfdb6f1..4260c20 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -686,7 +686,7 @@
     @Test
     public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnNullArgumentForCallback() {
         try {
-            mWifiManager.registerSoftApCallback(null, new HandlerExecutor(mHandler));
+            mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), null);
             fail("expected IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
         }
@@ -710,7 +710,7 @@
     @Test
     public void registerSoftApCallbackUsesMainLooperOnNullArgumentForHandler() {
         when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
-        mWifiManager.registerSoftApCallback(mSoftApCallback, null);
+        mWifiManager.registerSoftApCallback(null, mSoftApCallback);
         verify(mContext).getMainExecutor();
     }
 
@@ -719,7 +719,7 @@
      */
     @Test
     public void registerSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), anyInt());
     }
@@ -730,7 +730,7 @@
     @Test
     public void unregisterSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
         ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), callbackIdentifier.capture());
 
@@ -745,7 +745,7 @@
     public void softApCallbackProxyCallsOnStateChanged() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -761,7 +761,7 @@
     public void softApCallbackProxyCallsOnConnectedClientsChanged() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -778,7 +778,7 @@
     public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -802,7 +802,7 @@
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
         TestLooper altLooper = new TestLooper();
         Handler altHandler = new Handler(altLooper.getLooper());
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(altHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(altHandler), mSoftApCallback);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -816,7 +816,7 @@
      */
     @Test
     public void testCorrectLooperIsUsedForSoftApCallbackHandler() throws Exception {
-        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
+        mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback);
         mLooper.dispatchAll();
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), anyInt());