Merge "Allow ATV Keychord to turn on/off talkback"
diff --git a/Android.bp b/Android.bp
index aeb3ceb..ca1c614 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1084,53 +1084,63 @@
      "-federate SupportLib https://developer.android.com " +
      "-federationapi SupportLib $(location current/support-api.txt) "
 
-doc_defaults {
-    name: "api-stubs-default",
-    srcs: [
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        ":openjdk_javadoc_files",
-        ":non_openjdk_javadoc_files",
-        ":android_icu4j_src_files_for_docs",
-    ],
-    srcs_lib: "framework",
-    srcs_lib_whitelist_dirs: frameworks_base_subdirs,
-    srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "core-oj",
-        "core-libart",
-        "conscrypt",
-        "bouncycastle",
-        "okhttp",
-        "ext",
-        "framework",
-        "voip-common",
-        "android.test.mock.impl",
-    ],
-    local_sourcepaths: frameworks_base_subdirs,
-    html_dirs: [
-        "docs/html",
-    ],
-    knowntags: [
-        "docs/knowntags.txt",
-        ":known-oj-tags",
-    ],
-    custom_template: "droiddoc-templates-sdk",
-    hdf: [
-        "dac true",
-        "sdk.codename O",
-        "sdk.preview.version 1",
-        "sdk.version 7.0",
-        "sdk.rel.id 1",
-        "sdk.preview 0",
-    ],
-    resourcesdir: "docs/html/reference/images",
-    resourcesoutdir: "reference/android/images",
-    installable: false,
-}
+framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+     "-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.txt) "
 
-doc_defaults {
-    name: "framework-docs-default",
+framework_docs_only_libs = [
+    "conscrypt",
+    "bouncycastle",
+    "voip-common",
+    "android.test.mock",
+    "android-support-annotations",
+    "android-support-compat",
+    "android-support-core-ui",
+    "android-support-core-utils",
+    "android-support-customtabs",
+    "android-support-design",
+    "android-support-dynamic-animation",
+    "android-support-exifinterface",
+    "android-support-fragment",
+    "android-support-media-compat",
+    "android-support-percent",
+    "android-support-recommendation",
+    "android-support-transition",
+    "android-support-tv-provider",
+    "android-support-v7-cardview",
+    "android-support-v7-gridlayout",
+    "android-support-v7-mediarouter",
+    "android-support-v7-palette",
+    "android-support-v7-preference",
+    "android-support-v13",
+    "android-support-v14-preference",
+    "android-support-v17-leanback",
+    "android-support-v17-preference-leanback",
+    "android-support-wear",
+    "android-support-vectordrawable",
+    "android-support-animatedvectordrawable",
+    "android-support-v7-appcompat",
+    "android-support-v7-recyclerview",
+    "android-support-emoji",
+    "android-support-emoji-appcompat",
+    "android-support-emoji-bundled",
+    "android-support-v8-renderscript",
+    "android-support-multidex",
+    "android-support-multidex-instrumentation",
+]
+
+metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
+    "--hide-package com.android.okhttp " +
+    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
+    "--hide RequiresPermission " +
+    "--hide MissingPermission --hide BroadcastBehavior " +
+    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
+    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
+
+stubs_defaults {
+    name: "framework-doc-stubs-default",
     srcs: [
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
@@ -1144,47 +1154,25 @@
     srcs_lib: "framework",
     srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "conscrypt",
-        "bouncycastle",
-        "voip-common",
-        "android.test.mock",
-        "android-support-annotations",
-        "android-support-compat",
-        "android-support-core-ui",
-        "android-support-core-utils",
-        "android-support-customtabs",
-        "android-support-design",
-        "android-support-dynamic-animation",
-        "android-support-exifinterface",
-        "android-support-fragment",
-        "android-support-media-compat",
-        "android-support-percent",
-        "android-support-recommendation",
-        "android-support-transition",
-        "android-support-tv-provider",
-        "android-support-v7-cardview",
-        "android-support-v7-gridlayout",
-        "android-support-v7-mediarouter",
-        "android-support-v7-palette",
-        "android-support-v7-preference",
-        "android-support-v13",
-        "android-support-v14-preference",
-        "android-support-v17-leanback",
-        "android-support-v17-preference-leanback",
-        "android-support-wear",
-        "android-support-vectordrawable",
-        "android-support-animatedvectordrawable",
-        "android-support-v7-appcompat",
-        "android-support-v7-recyclerview",
-        "android-support-emoji",
-        "android-support-emoji-appcompat",
-        "android-support-emoji-bundled",
-        "android-support-v8-renderscript",
-        "android-support-multidex",
-        "android-support-multidex-instrumentation",
-    ],
+    libs: framework_docs_only_libs,
     local_sourcepaths: frameworks_base_subdirs,
+    create_doc_stubs: true,
+    annotations_enabled: true,
+    api_levels_annotations_enabled: true,
+    api_levels_annotations_dirs: [
+        "sdk-dir",
+        "api-versions-jars-dir",
+    ],
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-stubs",
+    ],
+}
+
+doc_defaults {
+    name: "framework-docs-default",
+    libs: framework_docs_only_libs,
     html_dirs: [
         "docs/html",
     ],
@@ -1205,23 +1193,13 @@
     ],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
         "core/java/overview.html",
         ":current-support-api",
-        "api/current.txt",
     ],
     create_stubs: false,
 }
 
-metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
-    "--hide-package com.android.okhttp " +
-    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
-    "--hide RequiresPermission " +
-    "--hide MissingPermission --hide BroadcastBehavior " +
-    "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
-    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
-
-doc_defaults {
+stubs_defaults {
     name: "metalava-api-stubs-default",
     srcs: [
         ":opt-telephony-srcs",
@@ -1246,30 +1224,53 @@
     ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
-    metalava_enabled: true,
-    metalava_annotations_enabled: true,
-    metalava_previous_api: ":last-released-public-api",
-    metalava_merge_annotations_dirs: [
+    annotations_enabled: true,
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
         "metalava-manual",
         "ojluni-annotated-stubs",
     ],
 }
 
+droidstubs {
+    name: "framework-doc-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args,
+}
+
+droidstubs {
+    name: "framework-doc-system-stubs",
+    defaults: ["framework-doc-stubs-default"],
+    arg_files: [
+        "core/res/AndroidManifest.xml",
+    ],
+    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
+}
+
 droiddoc {
     name: "doc-comment-check-docs",
     defaults: ["framework-docs-default"],
-    args: framework_docs_args + " -referenceonly -parsecomments",
+    srcs: [
+        ":framework-doc-stubs",
+    ],
+    args: framework_docs_only_args + " -referenceonly -parsecomments",
     installable: false,
 }
 
 droiddoc {
     name: "offline-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\"",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-preview-index.html",
 }
@@ -1277,11 +1278,14 @@
 droiddoc {
     name: "offline-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -offlinemode -title \"Android SDK\" -referenceonly",
+    args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1290,13 +1294,15 @@
 droiddoc {
     name: "offline-system-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc offline",
     ],
     proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
-    args: framework_docs_args + " -hide 101 -hide 104 -hide 108" +
-          " -showAnnotation android.annotation.SystemApi " +
-          " -offlinemode -title \"Android System SDK\" -referenceonly",
+    args: framework_docs_only_args  + " -hide 101 -hide 104 -hide 108" +
+        " -offlinemode -title \"Android System SDK\" -referenceonly",
     write_sdk_values: true,
     static_doc_index_redirect: "docs/docs-documentation-redirect.html",
     static_doc_properties: "docs/source.properties",
@@ -1305,12 +1311,15 @@
 droiddoc {
     name: "online-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args  +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1331,14 +1340,16 @@
 droiddoc {
     name: "online-system-api-sdk-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-system-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-system-api-sdk-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -referenceonly " +
-        " -showAnnotation android.annotation.SystemApi " +
         " -title \"Android SDK - Including system APIs.\" " +
         " -hide 101 " +
         " -hide 104 " +
@@ -1364,12 +1375,15 @@
 droiddoc {
     name: "ds-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "ds-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1390,11 +1404,14 @@
 droiddoc {
     name: "ds-static-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-static-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -staticonly " +
           " -toroot / " +
           " -devsite " +
@@ -1404,11 +1421,14 @@
 droiddoc {
     name: "ds-ref-navtree-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
     ],
     proofread_file: "ds-ref-navtree-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -toroot / " +
           " -atLinksNavtree " +
           " -navtreeonly ",
@@ -1417,12 +1437,15 @@
 droiddoc {
     name: "online-sdk-dev-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     hdf: [
         "android.whichdoc online",
         "android.hasSamples true",
     ],
     proofread_file: "online-sdk-dev-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
         " -toroot / -samplegroup Admin " +
         " -samplegroup Background " +
         " -samplegroup Connectivity " +
@@ -1443,13 +1466,16 @@
 droiddoc {
     name: "hidden-docs",
     defaults: ["framework-docs-default"],
+    srcs: [
+        ":framework-doc-stubs",
+    ],
     proofread_file: "hidden-docs-proofrerad.txt",
-    args: framework_docs_args +
+    args: framework_docs_only_args +
           " -referenceonly " +
           " -title \"Android SDK - Including hidden APIs.\"",
 }
 
-droiddoc {
+droidstubs {
     name: "hwbinder-stubs-docs",
     srcs: [
         "core/java/android/os/HidlSupport.java",
@@ -1467,10 +1493,15 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
-    custom_template: "droiddoc-templates-sdk",
     installable: false,
     no_framework_libs: true,
-    args: "-showAnnotation android.annotation.SystemApi -nodocs -stubsourceonly",
+    annotations_enabled: true,
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
+        "metalava-manual",
+        "ojluni-annotated-stubs",
+    ],
+    args: " --show-annotation android.annotation.SystemApi",
 }
 
 java_library_static {
@@ -1481,7 +1512,7 @@
     ],
 }
 
-droiddoc {
+droidstubs {
     name: "hiddenapi-lists-docs",
     defaults: ["metalava-api-stubs-default"],
     arg_files: [
@@ -1497,23 +1528,17 @@
 }
 
 
-droiddoc {
+droidstubs {
     name: "hiddenapi-mappings",
-    defaults: ["api-stubs-default"],
+    defaults: ["metalava-api-stubs-default"],
     arg_files: [
         "core/res/AndroidManifest.xml",
-        ":api-version-xml",
-        "core/java/overview.html",
-        ":current-support-api",
-        "api/current.txt",
     ],
     dex_mapping_filename: "dex-mapping.txt",
-    args: framework_docs_args +
-          " -referenceonly" +
-          " -nodocs" +
-          " -showUnannotated" +
-          " -showAnnotation android.annotation.SystemApi" +
-          " -showAnnotation android.annotation.TestApi",
+    args: metalava_framework_docs_args +
+        " --show-unannotated " +
+        " --show-annotation android.annotation.SystemApi " +
+        " --show-annotation android.annotation.TestApi "
 }
 
 filegroup {
@@ -1540,7 +1565,7 @@
     ],
 }
 
-droiddoc {
+droidstubs {
     name: "api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_filename: "public_api.txt",
@@ -1562,7 +1587,7 @@
     },
 }
 
-droiddoc {
+droidstubs {
     name: "system-api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_tag_name: "SYSTEM",
@@ -1586,7 +1611,7 @@
     },
 }
 
-droiddoc {
+droidstubs {
     name: "test-api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_tag_name: "TEST",
diff --git a/api/current.txt b/api/current.txt
index b9e00f6..1eecc2d 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -934,6 +934,7 @@
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
+    field public static final int minimumUiTimeout = 16844174; // 0x101058e
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
     field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -2874,10 +2875,12 @@
     method public int getCapabilities();
     method public deprecated java.lang.String getDescription();
     method public java.lang.String getId();
+    method public int getMinimumUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
+    method public void setMinimumUiTimeoutMillis(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
@@ -2902,6 +2905,7 @@
     field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
     field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 512; // 0x200
+    field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
     field public int eventTypes;
@@ -4382,6 +4386,7 @@
 
   public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
@@ -4389,11 +4394,13 @@
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
+    method public android.service.notification.ZenPolicy getZenPolicy();
     method public boolean isEnabled();
     method public void setConditionId(android.net.Uri);
     method public void setEnabled(boolean);
     method public void setInterruptionFilter(int);
     method public void setName(java.lang.String);
+    method public void setZenPolicy(android.service.notification.ZenPolicy);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
   }
@@ -9337,6 +9344,7 @@
     ctor public ContentUris();
     method public static android.net.Uri.Builder appendId(android.net.Uri.Builder, long);
     method public static long parseId(android.net.Uri);
+    method public static android.net.Uri removeId(android.net.Uri);
     method public static android.net.Uri withAppendedId(android.net.Uri, long);
   }
 
@@ -11925,6 +11933,7 @@
     method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+    method public float getFloat(int);
     method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
@@ -12652,7 +12661,7 @@
     ctor public SQLiteMisuseException(java.lang.String);
   }
 
-  public abstract class SQLiteOpenHelper {
+  public abstract class SQLiteOpenHelper implements java.lang.AutoCloseable {
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
     ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
@@ -14006,6 +14015,7 @@
     method public android.os.LocaleList getTextLocales();
     method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
     method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
+    method public float getTextRunAdvances(char[], int, int, int, int, boolean, float[], int);
     method public float getTextScaleX();
     method public float getTextSize();
     method public float getTextSkewX();
@@ -16030,6 +16040,7 @@
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
     method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
     method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
+    method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
     method public java.util.Set<java.lang.String> getPhysicalCameraIds();
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
@@ -36585,9 +36596,9 @@
     field public static final java.lang.String IS_PRIVATE = "isprivate";
     field public static final java.lang.String LATITUDE = "latitude";
     field public static final java.lang.String LONGITUDE = "longitude";
-    field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final java.lang.String ORIENTATION = "orientation";
-    field public static final java.lang.String PICASA_ID = "picasa_id";
+    field public static final deprecated java.lang.String PICASA_ID = "picasa_id";
   }
 
   public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
@@ -36690,7 +36701,7 @@
     field public static final java.lang.String LANGUAGE = "language";
     field public static final java.lang.String LATITUDE = "latitude";
     field public static final java.lang.String LONGITUDE = "longitude";
-    field public static final java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
     field public static final java.lang.String RESOLUTION = "resolution";
     field public static final java.lang.String TAGS = "tags";
   }
@@ -39562,6 +39573,7 @@
     method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
+    method public final void clearRequestedListenerHints();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
     method public final int getCurrentInterruptionFilter();
@@ -39677,6 +39689,61 @@
     field public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR;
   }
 
+  public final class ZenPolicy implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPriorityCallSenders();
+    method public int getPriorityCategoryAlarms();
+    method public int getPriorityCategoryCalls();
+    method public int getPriorityCategoryEvents();
+    method public int getPriorityCategoryMedia();
+    method public int getPriorityCategoryMessages();
+    method public int getPriorityCategoryReminders();
+    method public int getPriorityCategoryRepeatCallers();
+    method public int getPriorityCategorySystem();
+    method public int getPriorityMessageSenders();
+    method public int getVisualEffectAmbient();
+    method public int getVisualEffectBadge();
+    method public int getVisualEffectFullScreenIntent();
+    method public int getVisualEffectLights();
+    method public int getVisualEffectNotificationList();
+    method public int getVisualEffectPeek();
+    method public int getVisualEffectStatusBar();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.notification.ZenPolicy> CREATOR;
+    field public static final int PEOPLE_TYPE_ANYONE = 1; // 0x1
+    field public static final int PEOPLE_TYPE_CONTACTS = 2; // 0x2
+    field public static final int PEOPLE_TYPE_NONE = 4; // 0x4
+    field public static final int PEOPLE_TYPE_STARRED = 3; // 0x3
+    field public static final int PEOPLE_TYPE_UNSET = 0; // 0x0
+    field public static final int STATE_ALLOW = 1; // 0x1
+    field public static final int STATE_DISALLOW = 2; // 0x2
+    field public static final int STATE_UNSET = 0; // 0x0
+  }
+
+  public static class ZenPolicy.Builder {
+    ctor public ZenPolicy.Builder();
+    method public android.service.notification.ZenPolicy.Builder allowAlarms(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowAllSounds();
+    method public android.service.notification.ZenPolicy.Builder allowCalls(int);
+    method public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowMessages(int);
+    method public android.service.notification.ZenPolicy.Builder allowReminders(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean);
+    method public android.service.notification.ZenPolicy.Builder allowSystem(boolean);
+    method public android.service.notification.ZenPolicy build();
+    method public android.service.notification.ZenPolicy.Builder disallowAllSounds();
+    method public android.service.notification.ZenPolicy.Builder hideAllVisualEffects();
+    method public android.service.notification.ZenPolicy.Builder showAllVisualEffects();
+    method public android.service.notification.ZenPolicy.Builder showBadges(boolean);
+    method public android.service.notification.ZenPolicy.Builder showFullScreenIntent(boolean);
+    method public android.service.notification.ZenPolicy.Builder showInAmbientDisplay(boolean);
+    method public android.service.notification.ZenPolicy.Builder showInNotificationList(boolean);
+    method public android.service.notification.ZenPolicy.Builder showLights(boolean);
+    method public android.service.notification.ZenPolicy.Builder showPeeking(boolean);
+    method public android.service.notification.ZenPolicy.Builder showStatusBarIcons(boolean);
+  }
+
 }
 
 package android.service.quicksettings {
@@ -49547,6 +49614,7 @@
     method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
+    method public int getMinimumUiTimeoutMillis();
     method public void interrupt();
     method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1e1c621..79bbace 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -91,6 +91,7 @@
     field public static final java.lang.String KILL_UID = "android.permission.KILL_UID";
     field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
+    field public static final java.lang.String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
     field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
@@ -155,6 +156,7 @@
     field public static final java.lang.String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
     field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
+    field public static final java.lang.String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
     field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
     field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
@@ -355,6 +357,11 @@
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
   }
 
+  public final class AutomaticZenRule implements android.os.Parcelable {
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long);
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean, long, android.service.notification.ZenPolicy);
+  }
+
   public class BroadcastOptions {
     method public static android.app.BroadcastOptions makeBasic();
     method public void setDontSendToRestrictedApps(boolean);
@@ -3807,6 +3814,14 @@
     field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
   }
 
+  public class Environment {
+    method public static java.io.File getOdmDirectory();
+    method public static java.io.File getOemDirectory();
+    method public static java.io.File getProductDirectory();
+    method public static java.io.File getProductServicesDirectory();
+    method public static java.io.File getVendorDirectory();
+  }
+
   public class HidlSupport {
     method public static boolean deepEquals(java.lang.Object, java.lang.Object);
     method public static int deepHashCode(java.lang.Object);
@@ -4107,6 +4122,9 @@
     method public boolean isSystem();
     method public static int myUserId();
     method public static android.os.UserHandle of(int);
+    field public static final android.os.UserHandle ALL;
+    field public static final android.os.UserHandle CURRENT;
+    field public static final android.os.UserHandle SYSTEM;
     field public static final int USER_NULL = -10000; // 0xffffd8f0
   }
 
@@ -6785,7 +6803,6 @@
     method public static android.content.pm.PackageInfo getLoadedPackageInfo();
     method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
     method public static void prepareWebViewInZygote();
-    field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
     field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
     field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
     field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
diff --git a/api/test-current.txt b/api/test-current.txt
index 0f89dfd..e22f516 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -259,6 +259,7 @@
   }
 
   public abstract class Context {
+    method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String getOpPackageName();
     method public android.os.UserHandle getUser();
     method public int getUserId();
@@ -765,6 +766,8 @@
     method public static int getAppId(int);
     method public int getIdentifier();
     method public static boolean isApp(int);
+    field public static final android.os.UserHandle ALL;
+    field public static final android.os.UserHandle CURRENT;
     field public static final android.os.UserHandle SYSTEM;
   }
 
@@ -1336,30 +1339,47 @@
     method public void writeRawZigZag64(long);
   }
 
-  public final class ProtoOutputStream {
+  public final class ProtoInputStream extends android.util.proto.ProtoStream {
+    ctor public ProtoInputStream(java.io.InputStream, int);
+    ctor public ProtoInputStream(java.io.InputStream);
+    ctor public ProtoInputStream(byte[]);
+    method public int decodeZigZag32(int);
+    method public long decodeZigZag64(long);
+    method public java.lang.String dumpDebugData();
+    method public void end(long);
+    method public int getFieldNumber();
+    method public int getOffset();
+    method public int getWireType();
+    method public boolean isNextField(long) throws java.io.IOException;
+    method public int nextField() throws java.io.IOException;
+    method public boolean readBoolean(long) throws java.io.IOException;
+    method public byte[] readBytes(long) throws java.io.IOException;
+    method public double readDouble(long) throws java.io.IOException;
+    method public float readFloat(long) throws java.io.IOException;
+    method public int readInt(long) throws java.io.IOException;
+    method public long readLong(long) throws java.io.IOException;
+    method public java.lang.String readString(long) throws java.io.IOException;
+    method public void skip() throws java.io.IOException;
+    method public long start(long) throws java.io.IOException;
+    field public static final int NO_MORE_FIELDS = -1; // 0xffffffff
+  }
+
+  public final class ProtoOutputStream extends android.util.proto.ProtoStream {
     ctor public ProtoOutputStream();
     ctor public ProtoOutputStream(int);
     ctor public ProtoOutputStream(java.io.OutputStream);
     ctor public ProtoOutputStream(java.io.FileDescriptor);
     method public static int checkFieldId(long, long);
-    method public static int convertObjectIdToOrdinal(int);
     method public void dump(java.lang.String);
     method public void end(long);
     method public deprecated void endObject(long);
     method public deprecated void endRepeatedObject(long);
     method public void flush();
     method public byte[] getBytes();
-    method public static int getDepthFromToken(long);
-    method public static int getObjectIdFromToken(long);
-    method public static boolean getRepeatedFromToken(long);
-    method public static int getSizePosFromToken(long);
-    method public static int getTagSizeFromToken(long);
     method public static long makeFieldId(int, long);
-    method public static long makeToken(int, boolean, int, int, int);
     method public long start(long);
     method public deprecated long startObject(long);
     method public deprecated long startRepeatedObject(long);
-    method public static java.lang.String token2String(long);
     method public void write(long, double);
     method public void write(long, float);
     method public void write(long, int);
@@ -1416,6 +1436,27 @@
     method public void writeTag(int, int);
     method public deprecated void writeUInt32(long, int);
     method public deprecated void writeUInt64(long, long);
+  }
+
+  public class ProtoParseException extends java.lang.RuntimeException {
+    ctor public ProtoParseException(java.lang.String);
+  }
+
+  public abstract class ProtoStream {
+    ctor public ProtoStream();
+    method public static int convertObjectIdToOrdinal(int);
+    method public static int getDepthFromToken(long);
+    method public static java.lang.String getFieldCountString(long);
+    method public static java.lang.String getFieldIdString(long);
+    method public static java.lang.String getFieldTypeString(long);
+    method public static int getObjectIdFromToken(long);
+    method public static int getOffsetFromToken(long);
+    method public static boolean getRepeatedFromToken(long);
+    method public static int getTagSizeFromToken(long);
+    method public static java.lang.String getWireTypeString(int);
+    method public static long makeFieldId(int, long);
+    method public static long makeToken(int, boolean, int, int, int);
+    method public static java.lang.String token2String(long);
     field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
     field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
     field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
@@ -1435,6 +1476,7 @@
     field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
     field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
     field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+    field protected static final java.lang.String[] FIELD_TYPE_NAMES;
     field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
     field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
     field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
@@ -1444,7 +1486,6 @@
     field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
     field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
     field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
-    field public static final java.lang.String TAG = "ProtoOutputStream";
     field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
     field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
     field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
@@ -1454,8 +1495,8 @@
     field public static final int WIRE_TYPE_VARINT = 0; // 0x0
   }
 
-  public class ProtoParseException extends java.lang.RuntimeException {
-    ctor public ProtoParseException(java.lang.String);
+  public class WireTypeMismatchException extends android.util.proto.ProtoParseException {
+    ctor public WireTypeMismatchException(java.lang.String);
   }
 
 }
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 302b4ef..86d956f 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -171,7 +171,7 @@
  */
 class TombstoneSection : public WorkerThreadSection {
 public:
-    TombstoneSection(int id, const char* type, int64_t timeoutMs = 30000 /* 30 seconds */);
+    TombstoneSection(int id, const char* type, int64_t timeoutMs = 120000 /* 2 minutes */);
     virtual ~TombstoneSection();
 
     virtual status_t BlockingCall(int pipeWriteFd) const;
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index b11e843..e14f2eb 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -207,7 +207,14 @@
 
     result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
 
-    if (base == NULL) {
+    if (base == nullptr || result != NO_ERROR) {
+        String8 reason;
+        if (base == nullptr) {
+            reason = "Failed to write to buffer";
+        } else {
+            reason.appendFormat("Error Code: %d", result);
+        }
+        fprintf(stderr, "Failed to take screenshot (%s)\n", reason.c_str());
         close(fd);
         return 1;
     }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d117f39..786e76c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -91,7 +91,7 @@
         ActivityForegroundStateChanged activity_foreground_state_changed = 42;
         IsolatedUidChanged isolated_uid_changed = 43;
         PacketWakeupOccurred packet_wakeup_occurred = 44;
-        // 45 is available
+        WallClockTimeShifted wall_clock_time_shifted = 45;
         AnomalyDetected anomaly_detected = 46;
         AppBreadcrumbReported app_breadcrumb_reported = 47;
         AppStartOccurred app_start_occurred = 48;
@@ -132,6 +132,7 @@
         KeyValuePairsAtom key_value_pairs_atom = 83;
         VibratorStateChanged vibrator_state_changed = 84;
         DeferredJobStatsReported deferred_job_stats_reported = 85;
+        ThermalThrottlingStateChanged thermal_throttling = 86;
     }
 
     // Pulled events will start at field 10000.
@@ -167,6 +168,7 @@
         AppSize app_size = 10027;
         CategorySize category_size = 10028;
         android.service.procstats.ProcessStatsSectionProto proc_stats = 10029;
+        BatteryVoltage battery_voltage = 10030;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -229,6 +231,26 @@
  */
 
 /**
+ * Logs when the Thermal service HAL notifies the throttling start/stop events.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
+ */
+message ThermalThrottlingStateChanged {
+    optional android.os.TemperatureTypeEnum sensor_type = 1;
+
+    enum State {
+        UNKNOWN = 0;
+        START = 1;
+        STOP = 2;
+    }
+
+    optional State state = 2;
+
+    optional float temperature = 3;
+}
+
+/**
  * Logs when the screen state changes.
  *
  * Logged from:
@@ -1479,6 +1501,18 @@
 }
 
 /**
+ * Logs the wall-clock time when a significant wall-clock time shift occurs.
+ * For example, this could be due to the user manually changing the time.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
+ */
+message WallClockTimeShifted {
+    // New wall-clock time in milliseconds, according to System.currentTimeMillis().
+    optional int64 wall_clock_timestamp_millis = 1;
+}
+
+/**
  * Logs when statsd detects an anomaly.
  *
  * Logged from:
@@ -2143,6 +2177,16 @@
 }
 
 /**
+ * Pulls battery voltage.
+ * Pulled from:
+ *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ */
+message BatteryVoltage {
+    // The voltage of the battery, in millivolts.
+    optional int32 voltage_mV = 1;
+}
+
+/**
  * Pulls the temperature of various parts of the device.
  * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303.
  *
@@ -2163,8 +2207,8 @@
 /**
  * Pulls the statistics of calls to Binder.
  *
- * Binder stats are cumulative from boot unless somebody reset the data using
- * > adb shell dumpsys binder_calls_stats --reset
+ * Binder stats will be reset every time the data is pulled. It means it can only be pulled by one
+ * config on the device.
  *
  * Next tag: 14
  */
@@ -2228,6 +2272,14 @@
     optional int64 exception_count = 2;
 }
 
+/**
+ * Pulls the statistics of message dispatching on HandlerThreads.
+ *
+ * Looper stats will be reset every time the data is pulled. It means it can only be pulled by one
+ * config on the device.
+ *
+ * Next tag: 11
+ */
 message LooperStats {
     // Currently not collected and always set to 0.
     optional int32 uid = 1 [(is_uid) = true];
@@ -2271,8 +2323,11 @@
     // Total CPU usage of all processed message.
     // Average can be computed using recorded_total_cpu_micros /
     // recorded_message_count. Total can be computed using
-    // recorded_total_cpu_micros / recorded_message_count * call_count.
+    // recorded_total_cpu_micros / recorded_message_count * message_count.
     optional int64 recorded_total_cpu_micros = 9;
+
+    // True if the screen was interactive PowerManager#isInteractive at the end of the call.
+    optional bool screen_interactive = 10;
 }
 
 /**
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index ae97d7a..ae2cf74 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -67,6 +67,7 @@
     data->clear();
     bool result_success = true;
 
+    // Get the data from the Health HAL (hardware/interfaces/health/1.0/types.hal).
     Return<void> ret = gHealthHal->getHealthInfo([&](Result r, HealthInfo v) {
         if (r != Result::SUCCESS) {
             result_success = false;
@@ -84,6 +85,12 @@
             ptr->write(v.legacy.batteryFullCharge);
             ptr->init();
             data->push_back(ptr);
+        } else if (mTagId == android::util::BATTERY_VOLTAGE) {
+            auto ptr = make_shared<LogEvent>(android::util::BATTERY_VOLTAGE,
+                wallClockTimestampNs, elapsedTimestampNs);
+            ptr->write(v.legacy.batteryVoltage);
+            ptr->init();
+            data->push_back(ptr);
         } else {
             ALOGE("Unsupported tag in ResourceHealthManagerPuller: %d", mTagId);
         }
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index dbc13dc..745ff74 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -161,6 +161,12 @@
           {},
           1 * NS_PER_SEC,
           new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+        // battery_voltage
+        {android::util::BATTERY_VOLTAGE,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
         // process_memory_state
         {android::util::PROCESS_MEMORY_STATE,
          {{4, 5, 6, 7, 8},
@@ -168,7 +174,7 @@
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
         // temperature
-        {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}},
+        {android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
         // binder_calls
         {android::util::BINDER_CALLS,
          {{4, 5, 6, 8, 12},
@@ -184,7 +190,7 @@
         // looper_stats
         {android::util::LOOPER_STATS,
          {{5, 6, 7, 8, 9},
-          {2, 3, 4},
+          {2, 3, 4, 10},
           1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
         // Disk Stats
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index eec90fc..afd8ec2 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -49,7 +49,6 @@
 // for EventMetricData
 const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1;
 const int FIELD_ID_ATOMS = 2;
-const int FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS = 3;
 
 EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
                                          const int conditionIndex,
@@ -146,13 +145,9 @@
     if (truncateTimestamp) {
         mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
             (long long)truncateTimestampNsToFiveMinutes(event.GetElapsedTimestampNs()));
-        mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
-            (long long)truncateTimestampNsToFiveMinutes(getWallClockNs()));
     } else {
         mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
             (long long)event.GetElapsedTimestampNs());
-        mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
-            (long long)getWallClockNs());
     }
 
     uint64_t eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index bcfcd7a..02b9773 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -63,7 +63,6 @@
 // for GaugeBucketInfo
 const int FIELD_ID_ATOM = 3;
 const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
-const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5;
 const int FIELD_ID_BUCKET_NUM = 6;
 const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7;
 const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
@@ -286,16 +285,9 @@
                     const int64_t elapsedTimestampNs =  truncateTimestamp ?
                         truncateTimestampNsToFiveMinutes(atom.mElapsedTimestamps) :
                             atom.mElapsedTimestamps;
-                    const int64_t wallClockNs = truncateTimestamp ?
-                        truncateTimestampNsToFiveMinutes(atom.mWallClockTimestampNs) :
-                            atom.mWallClockTimestampNs;
                     protoOutput->write(
                         FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
                         (long long)elapsedTimestampNs);
-                    protoOutput->write(
-                        FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
-                            FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP,
-                        (long long)wallClockNs);
                 }
             }
             protoOutput->end(bucketInfoToken);
@@ -450,7 +442,7 @@
     if ((*mCurrentSlicedBucket)[eventKey].size() >= mGaugeAtomsPerDimensionLimit) {
         return;
     }
-    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs, getWallClockNs());
+    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs);
     (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
     // Anomaly detection on gauge metric only works when there is one numeric
     // field specified.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index e3da5db..6379389 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -33,12 +33,11 @@
 namespace statsd {
 
 struct GaugeAtom {
-    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs, int64_t wallClockNs)
-        : mFields(fields), mElapsedTimestamps(elapsedTimeNs), mWallClockTimestampNs(wallClockNs) {
+    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs)
+        : mFields(fields), mElapsedTimestamps(elapsedTimeNs) {
     }
     std::shared_ptr<vector<FieldValue>> mFields;
     int64_t mElapsedTimestamps;
-    int64_t mWallClockTimestampNs;
 };
 
 struct GaugeBucket {
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index db7e680..ab0b23c 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -46,7 +46,7 @@
 
   optional Atom atom = 2;
 
-  optional int64 wall_clock_timestamp_nanos = 3;
+  optional int64 wall_clock_timestamp_nanos = 3 [deprecated = true];
 }
 
 message CountBucketInfo {
@@ -142,7 +142,7 @@
 
   repeated int64 elapsed_timestamp_nanos = 4;
 
-  repeated int64 wall_clock_timestamp_nanos = 5;
+  repeated int64 wall_clock_timestamp_nanos = 5 [deprecated = true];
 
   optional int64 bucket_num = 6;
 
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index ea6eb3f..5b6f167 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -148,7 +148,7 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
@@ -271,7 +271,7 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
@@ -375,7 +375,6 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 3de8d0d..5c1ef01 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -173,7 +173,7 @@
         if (sampling_type == GaugeMetric::ALL_CONDITION_CHANGES) {
             EXPECT_EQ(2, data.bucket_info(0).atom_size());
             EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+            EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -192,7 +192,6 @@
 
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(1).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -206,7 +205,6 @@
 
             EXPECT_EQ(2, data.bucket_info(2).atom_size());
             EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                       data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -226,7 +224,6 @@
         } else {
             EXPECT_EQ(1, data.bucket_info(0).atom_size());
             EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -239,7 +236,6 @@
 
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(1).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -253,7 +249,6 @@
 
             EXPECT_EQ(1, data.bucket_info(2).atom_size());
             EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                       data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -276,7 +271,6 @@
         EXPECT_EQ(1, data.bucket_info_size());
         EXPECT_EQ(1, data.bucket_info(0).atom_size());
         EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-        EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
         EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                   data.bucket_info(0).start_bucket_elapsed_nanos());
         EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 04b33b1..b683138 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -15605,7 +15605,6 @@
 HSPLandroid/app/admin/IDevicePolicyManager;->getLockTaskPackages(Landroid/content/ComponentName;)[Ljava/lang/String;
 HSPLandroid/app/admin/IDevicePolicyManager;->getLongSupportMessage(Landroid/content/ComponentName;)Ljava/lang/CharSequence;
 HSPLandroid/app/admin/IDevicePolicyManager;->getLongSupportMessageForUser(Landroid/content/ComponentName;I)Ljava/lang/CharSequence;
-HSPLandroid/app/admin/IDevicePolicyManager;->getMandatoryBackupTransport()Landroid/content/ComponentName;
 HSPLandroid/app/admin/IDevicePolicyManager;->getMaximumFailedPasswordsForWipe(Landroid/content/ComponentName;IZ)I
 HSPLandroid/app/admin/IDevicePolicyManager;->getMaximumTimeToLock(Landroid/content/ComponentName;IZ)J
 HSPLandroid/app/admin/IDevicePolicyManager;->getMeteredDataDisabledPackages(Landroid/content/ComponentName;)Ljava/util/List;
@@ -15747,7 +15746,6 @@
 HSPLandroid/app/admin/IDevicePolicyManager;->setLockTaskPackages(Landroid/content/ComponentName;[Ljava/lang/String;)V
 HSPLandroid/app/admin/IDevicePolicyManager;->setLogoutEnabled(Landroid/content/ComponentName;Z)V
 HSPLandroid/app/admin/IDevicePolicyManager;->setLongSupportMessage(Landroid/content/ComponentName;Ljava/lang/CharSequence;)V
-HSPLandroid/app/admin/IDevicePolicyManager;->setMandatoryBackupTransport(Landroid/content/ComponentName;Landroid/content/ComponentName;)Z
 HSPLandroid/app/admin/IDevicePolicyManager;->setMasterVolumeMuted(Landroid/content/ComponentName;Z)V
 HSPLandroid/app/admin/IDevicePolicyManager;->setMaximumFailedPasswordsForWipe(Landroid/content/ComponentName;IZ)V
 HSPLandroid/app/admin/IDevicePolicyManager;->setMaximumTimeToLock(Landroid/content/ComponentName;JZ)V
@@ -24288,7 +24286,6 @@
 HSPLandroid/inputmethodservice/IInputMethodSessionWrapper;->getInternalInputMethodSession()Landroid/view/inputmethod/InputMethodSession;
 HSPLandroid/inputmethodservice/IInputMethodWrapper$InputMethodSessionCallbackWrapper;->sessionCreated(Landroid/view/inputmethod/InputMethodSession;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;-><init>(Landroid/inputmethodservice/AbstractInputMethodService;Landroid/view/inputmethod/InputMethod;)V
-HSPLandroid/inputmethodservice/IInputMethodWrapper;->attachToken(Landroid/os/IBinder;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->bindInput(Landroid/view/inputmethod/InputBinding;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->createSession(Landroid/view/InputChannel;Lcom/android/internal/view/IInputSessionCallback;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->executeMessage(Landroid/os/Message;)V
@@ -42280,11 +42277,9 @@
 HSPLcom/android/internal/view/IInputContextCallback;->setTextAfterCursor(Ljava/lang/CharSequence;I)V
 HSPLcom/android/internal/view/IInputContextCallback;->setTextBeforeCursor(Ljava/lang/CharSequence;I)V
 HSPLcom/android/internal/view/IInputMethod$Stub$Proxy;->asBinder()Landroid/os/IBinder;
-HSPLcom/android/internal/view/IInputMethod$Stub$Proxy;->attachToken(Landroid/os/IBinder;)V
 HSPLcom/android/internal/view/IInputMethod$Stub;-><init>()V
 HSPLcom/android/internal/view/IInputMethod$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethod;
 HSPLcom/android/internal/view/IInputMethod$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
-HSPLcom/android/internal/view/IInputMethod;->attachToken(Landroid/os/IBinder;)V
 HSPLcom/android/internal/view/IInputMethod;->bindInput(Landroid/view/inputmethod/InputBinding;)V
 HSPLcom/android/internal/view/IInputMethod;->changeInputMethodSubtype(Landroid/view/inputmethod/InputMethodSubtype;)V
 HSPLcom/android/internal/view/IInputMethod;->createSession(Landroid/view/InputChannel;Lcom/android/internal/view/IInputSessionCallback;)V
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index a4f13a0..8c347fc 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -728,8 +728,6 @@
 Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
 Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
 Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
-Landroid/os/Environment;->getOemDirectory()Ljava/io/File;
-Landroid/os/Environment;->getVendorDirectory()Ljava/io/File;
 Landroid/os/Environment;->initForCurrentUser()V
 Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
 Landroid/os/Environment;->sCurrentUser:Landroid/os/Environment$UserEnvironment;
@@ -1001,8 +999,6 @@
 Landroid/os/UserHandle;->AID_CACHE_GID_START:I
 Landroid/os/UserHandle;->AID_ROOT:I
 Landroid/os/UserHandle;->AID_SHARED_GID_START:I
-Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
-Landroid/os/UserHandle;->CURRENT:Landroid/os/UserHandle;
 Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle;
 Landroid/os/UserHandle;->ERR_GID:I
 Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
@@ -2226,13 +2222,6 @@
 Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V
 Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostname()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getHostnameOrIP()Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getSoWriteTimeout()I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHandshakeTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setHostname(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setSoWriteTimeout(I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->socket:Ljava/net/Socket;
 Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V
 Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
 Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f..50e97c5 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1436,12 +1436,6 @@
 android.hardware.usb.UsbDeviceConnection
 android.hardware.usb.UsbManager
 android.hardware.usb.UsbRequest
-android.hidl.base.V1_0.DebugInfo
-android.hidl.base.V1_0.IBase
-android.hidl.manager.V1_0.IServiceManager
-android.hidl.manager.V1_0.IServiceManager$Proxy
-android.hidl.manager.V1_0.IServiceNotification
-android.hidl.manager.V1_0.IServiceNotification$Stub
 android.icu.impl.BMPSet
 android.icu.impl.CacheBase
 android.icu.impl.CacheValue
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 446e6cc..f2ad268 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -73,7 +74,7 @@
  * follows the established service life cycle. Starting an accessibility service is triggered
  * exclusively by the user explicitly turning the service on in device settings. After the system
  * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
- * be overriden by clients that want to perform post binding setup.
+ * be overridden by clients that want to perform post binding setup.
  * </p>
  * <p>
  * An accessibility service stops either when the user turns it off in device settings or when
@@ -446,7 +447,7 @@
     @UnsupportedAppUsage
     private AccessibilityServiceInfo mInfo;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private IBinder mWindowToken;
 
     private WindowManager mWindowManager;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index f0a0e88..aa0275a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -76,6 +76,7 @@
  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
  * @attr ref android.R.styleable#AccessibilityService_packageNames
  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
+ * @attr ref android.R.styleable#AccessibilityService_minimumUiTimeout
  * @see AccessibilityService
  * @see android.view.accessibility.AccessibilityEvent
  * @see android.view.accessibility.AccessibilityManager
@@ -313,6 +314,12 @@
      */
     public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200;
 
+    /**
+     * This flag requests that accessibility shortcut warning dialog has spoken feedback when
+     * dialog is shown.
+     */
+    public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400;
+
     /** {@hide} */
     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
 
@@ -413,6 +420,7 @@
      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
+     * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
      */
     public int flags;
 
@@ -426,6 +434,13 @@
     public boolean crashed;
 
     /**
+     * The minimum timeout in milliseconds that UI controls need to remain on the screen.
+     *
+     * @see #setMinimumUiTimeoutMillis
+     */
+    private int mMinimumUiTimeout;
+
+    /**
      * The component name the accessibility service.
      */
     private ComponentName mComponentName;
@@ -529,6 +544,9 @@
             notificationTimeout = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
                     0);
+            mMinimumUiTimeout = asAttributes.getInt(
+                    com.android.internal.R.styleable.AccessibilityService_minimumUiTimeout,
+                    0);
             flags = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
             mSettingsActivityName = asAttributes.getString(
@@ -598,6 +616,7 @@
         packageNames = other.packageNames;
         feedbackType = other.feedbackType;
         notificationTimeout = other.notificationTimeout;
+        mMinimumUiTimeout = other.mMinimumUiTimeout;
         flags = other.flags;
     }
 
@@ -755,6 +774,29 @@
         return null;
     }
 
+    /**
+     * Set the minimum time that controls need to remain on the screen to support the user.
+     * <p>
+     *    <strong>This value can be dynamically set at runtime by
+     *    {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+     * </p>
+     *
+     * @param timeout The timeout in milliseconds.
+     */
+    public void setMinimumUiTimeoutMillis(int timeout) {
+        mMinimumUiTimeout = timeout;
+    }
+
+    /**
+     * Get the minimum ui timeout.
+     *
+     * @see #setMinimumUiTimeoutMillis
+     * @return The timeout in milliseconds.
+     */
+    public int getMinimumUiTimeoutMillis() {
+        return mMinimumUiTimeout;
+    }
+
     /** {@hide} */
     public boolean isDirectBootAware() {
         return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
@@ -773,6 +815,7 @@
         parcel.writeStringArray(packageNames);
         parcel.writeInt(feedbackType);
         parcel.writeLong(notificationTimeout);
+        parcel.writeInt(mMinimumUiTimeout);
         parcel.writeInt(flags);
         parcel.writeInt(crashed ? 1 : 0);
         parcel.writeParcelable(mComponentName, flagz);
@@ -790,6 +833,7 @@
         packageNames = parcel.readStringArray();
         feedbackType = parcel.readInt();
         notificationTimeout = parcel.readLong();
+        mMinimumUiTimeout = parcel.readInt();
         flags = parcel.readInt();
         crashed = parcel.readInt() != 0;
         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
@@ -840,6 +884,8 @@
         stringBuilder.append(", ");
         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
         stringBuilder.append(", ");
+        stringBuilder.append("minimumUiTimeout: ").append(mMinimumUiTimeout);
+        stringBuilder.append(", ");
         appendFlags(stringBuilder, flags);
         stringBuilder.append(", ");
         stringBuilder.append("id: ").append(getId());
@@ -1011,6 +1057,8 @@
                 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
             case FLAG_REQUEST_FINGERPRINT_GESTURES:
                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
+            case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
+                return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
             default:
                 return null;
         }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bf2d860..5499d59 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -847,7 +847,7 @@
     /*package*/ ActionBar mActionBar = null;
     private boolean mEnableDefaultActionBarUp;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private VoiceInteractor mVoiceInteractor;
 
     @UnsupportedAppUsage
@@ -2310,7 +2310,7 @@
      *
      * @param newConfig The new device configuration.
      */
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onConfigurationChanged " + this + ": " + newConfig);
         mCalled = true;
 
@@ -3523,7 +3523,7 @@
      * {@link android.view.Window#FEATURE_OPTIONS_PANEL} panel,
      * so that subclasses of Activity don't need to deal with feature codes.
      */
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+    public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             boolean show = onCreateOptionsMenu(menu);
             show |= mFragments.dispatchCreateOptionsMenu(menu, getMenuInflater());
@@ -3541,8 +3541,8 @@
      * panel, so that subclasses of
      * Activity don't need to deal with feature codes.
      */
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
+    public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) {
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             boolean goforit = onPrepareOptionsMenu(menu);
             goforit |= mFragments.dispatchPrepareOptionsMenu(menu);
             return goforit;
@@ -3555,7 +3555,8 @@
      *
      * @return The default implementation returns true.
      */
-    public boolean onMenuOpened(int featureId, Menu menu) {
+    @Override
+    public boolean onMenuOpened(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             initWindowDecorActionBar();
             if (mActionBar != null) {
@@ -3576,7 +3577,7 @@
      * panel, so that subclasses of
      * Activity don't need to deal with feature codes.
      */
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
         CharSequence titleCondensed = item.getTitleCondensed();
 
         switch (featureId) {
@@ -3626,7 +3627,7 @@
      * For context menus ({@link Window#FEATURE_CONTEXT_MENU}), the
      * {@link #onContextMenuClosed(Menu)} will be called.
      */
-    public void onPanelClosed(int featureId, Menu menu) {
+    public void onPanelClosed(int featureId, @NonNull Menu menu) {
         switch (featureId) {
             case Window.FEATURE_OPTIONS_PANEL:
                 mFragments.dispatchOptionsMenuClosed(menu);
@@ -3734,7 +3735,7 @@
      *
      * @see #onCreateOptionsMenu
      */
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         if (mParent != null) {
             return mParent.onOptionsItemSelected(item);
         }
@@ -3958,7 +3959,7 @@
      * @return boolean Return false to allow normal context menu processing to
      *         proceed, true to consume it here.
      */
-    public boolean onContextItemSelected(MenuItem item) {
+    public boolean onContextItemSelected(@NonNull MenuItem item) {
         if (mParent != null) {
             return mParent.onContextItemSelected(item);
         }
@@ -3972,7 +3973,7 @@
      *
      * @param menu The context menu that is being closed.
      */
-    public void onContextMenuClosed(Menu menu) {
+    public void onContextMenuClosed(@NonNull Menu menu) {
         if (mParent != null) {
             mParent.onContextMenuClosed(menu);
         }
@@ -6350,7 +6351,8 @@
      * @see android.view.Window#getLayoutInflater
      */
     @Nullable
-    public View onCreateView(String name, Context context, AttributeSet attrs) {
+    public View onCreateView(@NonNull String name, @NonNull Context context,
+            @NonNull AttributeSet attrs) {
         return null;
     }
 
@@ -6364,7 +6366,9 @@
      * @see android.view.LayoutInflater#createView
      * @see android.view.Window#getLayoutInflater
      */
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+    @Nullable
+    public View onCreateView(@Nullable View parent, @NonNull String name,
+            @NonNull Context context, @NonNull AttributeSet attrs) {
         if (!"fragment".equals(name)) {
             return onCreateView(name, context, attrs);
         }
@@ -6382,11 +6386,13 @@
      * closed for you after you return.
      * @param args additional arguments to the dump request.
      */
-    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd,
+            @NonNull PrintWriter writer, @Nullable String[] args) {
         dumpInner(prefix, fd, writer, args);
     }
 
-    void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+    void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
+            @NonNull PrintWriter writer, @Nullable String[] args) {
         if (args != null && args.length > 0 && args[0].equals("--autofill")) {
             dumpAutofillManager(prefix, writer);
             return;
@@ -7094,7 +7100,7 @@
 
     // ------------------ Internal API ------------------
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final void setParent(Activity parent) {
         mParent = parent;
     }
@@ -7205,7 +7211,7 @@
         mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
     }
 
-    final void performNewIntent(Intent intent) {
+    final void performNewIntent(@NonNull Intent intent) {
         mCanEnterPictureInPicture = true;
         onNewIntent(intent);
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8354235..e86a49d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1221,7 +1221,7 @@
          * @return The background color.
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int getBackgroundColor() {
             return mColorBackground;
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9120701..31e9a2d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -340,7 +340,7 @@
     // An executor that performs multi-step transactions.
     private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ResourcesManager mResourcesManager;
 
     private static final class ProviderKey {
@@ -374,7 +374,7 @@
     @UnsupportedAppUsage
     final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
         = new ArrayMap<IBinder, ProviderRefCount>();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
         = new ArrayMap<IBinder, ProviderClientRecord>();
     @UnsupportedAppUsage
@@ -394,7 +394,7 @@
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     static volatile Handler sMainThreadHandler;  // set once in main()
 
     Bundle mCoreSettings = null;
@@ -456,7 +456,7 @@
         private int mLifecycleState = PRE_ON_CREATE;
 
         @VisibleForTesting
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public ActivityClientRecord() {
             this.isForward = false;
             init();
@@ -704,7 +704,7 @@
         @UnsupportedAppUsage
         boolean persistent;
         Configuration config;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         CompatibilityInfo compatInfo;
         String buildSerial;
 
@@ -2088,7 +2088,7 @@
         return mH;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
             int flags) {
         return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId());
@@ -2131,7 +2131,7 @@
             ai = getPackageManager().getApplicationInfo(packageName,
                     PackageManager.GET_SHARED_LIBRARY_FILES
                             | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                    userId);
+                    (userId < 0) ? UserHandle.myUserId() : userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2177,7 +2177,7 @@
         return getPackageInfo(ai, compatInfo, null, false, true, false);
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
         synchronized (mResourcesManager) {
             WeakReference<LoadedApk> ref;
@@ -2850,7 +2850,7 @@
         return aInfo;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Activity startActivityNow(Activity parent, String id,
         Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
         Activity.NonConfigurationInstances lastNonConfigurationInstances) {
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index dbc8c5d..cf40e06 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -397,7 +397,7 @@
      * @param listener The {@link DialogInterface.OnClickListener} to use.
      * @deprecated Use
      *             {@link #setButton(int, CharSequence, android.content.DialogInterface.OnClickListener)}
-     *             with {@link DialogInterface#BUTTON_POSITIVE}
+     *             with {@link DialogInterface#BUTTON_NEUTRAL}
      */
     @Deprecated
     public void setButton3(CharSequence text, final OnClickListener listener) {
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 636366d..68b745d 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -127,7 +127,7 @@
     }
 
     @CallSuper
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
         Object[] callbacks = collectComponentCallbacks();
         if (callbacks != null) {
             for (int i=0; i<callbacks.length; i++) {
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index cd4ace6..62f6bac 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,11 +16,14 @@
 
 package android.app;
 
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+
 import android.app.NotificationManager.InterruptionFilter;
 import android.content.ComponentName;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.service.notification.ZenPolicy;
 
 import java.util.Objects;
 
@@ -35,6 +38,7 @@
     private Uri conditionId;
     private ComponentName owner;
     private long creationTime;
+    private ZenPolicy mZenPolicy;
 
     /**
      * Creates an automatic zen rule.
@@ -58,7 +62,27 @@
     }
 
     /**
-     * @SystemApi
+     * Creates an automatic zen rule.
+     *
+     * @param name The name of the rule.
+     * @param owner The Condition Provider service that owns this rule.
+     * @param conditionId A representation of the state that should cause the Condition Provider
+     *                    service to apply the given interruption filter.
+     * @param policy The policy defines which notifications are allowed to interrupt the user
+     *               while this rule is active
+     * @param enabled Whether the rule is enabled.
+     */
+    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+            boolean enabled) {
+        this.name = name;
+        this.owner = owner;
+        this.conditionId = conditionId;
+        this.interruptionFilter = INTERRUPTION_FILTER_PRIORITY;
+        this.enabled = enabled;
+        this.mZenPolicy = policy;
+    }
+
+    /**
      * @hide
      */
     public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
@@ -67,6 +91,15 @@
         this.creationTime = creationTime;
     }
 
+    /**
+     * @hide
+     */
+    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
+            boolean enabled, long creationTime) {
+        this(name, owner, conditionId, policy, enabled);
+        this.creationTime = creationTime;
+    }
+
     public AutomaticZenRule(Parcel source) {
         enabled = source.readInt() == 1;
         if (source.readInt() == 1) {
@@ -76,6 +109,7 @@
         conditionId = source.readParcelable(null);
         owner = source.readParcelable(null);
         creationTime = source.readLong();
+        mZenPolicy = source.readParcelable(null);
     }
 
     /**
@@ -114,6 +148,13 @@
     }
 
     /**
+     * Gets the zen policy.
+     */
+    public ZenPolicy getZenPolicy() {
+        return this.mZenPolicy.copy();
+    }
+
+    /**
      * Returns the time this rule was created, represented as milliseconds since the epoch.
      */
     public long getCreationTime() {
@@ -149,6 +190,13 @@
         this.enabled = enabled;
     }
 
+    /**
+     * Sets the zen policy.
+     */
+    public void setZenPolicy(ZenPolicy zenPolicy) {
+        this.mZenPolicy = zenPolicy;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -167,6 +215,7 @@
         dest.writeParcelable(conditionId, 0);
         dest.writeParcelable(owner, 0);
         dest.writeLong(creationTime);
+        dest.writeParcelable(mZenPolicy, 0);
     }
 
     @Override
@@ -178,6 +227,7 @@
                 .append(",conditionId=").append(conditionId)
                 .append(",owner=").append(owner)
                 .append(",creationTime=").append(creationTime)
+                .append(",mZenPolicy=").append(mZenPolicy)
                 .append(']').toString();
     }
 
@@ -191,12 +241,14 @@
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
                 && Objects.equals(other.owner, owner)
-                && other.creationTime == creationTime;
+                && other.creationTime == creationTime
+                && Objects.equals(other.mZenPolicy, mZenPolicy);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime);
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime,
+                mZenPolicy);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/ContentProviderHolder.java b/core/java/android/app/ContentProviderHolder.java
index 1098990..2a13c71 100644
--- a/core/java/android/app/ContentProviderHolder.java
+++ b/core/java/android/app/ContentProviderHolder.java
@@ -20,6 +20,7 @@
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
 import android.content.pm.ProviderInfo;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -35,7 +36,7 @@
     @UnsupportedAppUsage
     public IContentProvider provider;
     public IBinder connection;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean noReleaseNeeded;
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bbaaee8..77f6395 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -164,7 +164,7 @@
      * Map from preference name to generated path.
      */
     @GuardedBy("ContextImpl.class")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ArrayMap<String, File> mSharedPrefsPaths;
 
     @UnsupportedAppUsage
@@ -183,7 +183,7 @@
 
     @UnsupportedAppUsage
     private final String mBasePackageName;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mOpPackageName;
 
     private final @NonNull ResourcesManager mResourcesManager;
@@ -191,7 +191,7 @@
     private @NonNull Resources mResources;
     private @Nullable Display mDisplay; // may be null if default display
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mFlags;
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index b7bac52..6bcfb2e 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -34,6 +34,7 @@
 import android.content.res.ResourceId;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -133,7 +134,7 @@
     private final Handler mHandler = new Handler();
 
     private static final int DISMISS = 0x43;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final int CANCEL = 0x44;
     private static final int SHOW = 0x45;
 
@@ -936,8 +937,8 @@
      * @see Activity#onPreparePanel(int, View, Menu)
      */
     @Override
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
+    public boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu) {
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
             return onPrepareOptionsMenu(menu) && menu.hasVisibleItems();
         }
         return true;
@@ -947,7 +948,7 @@
      * @see Activity#onMenuOpened(int, Menu)
      */
     @Override
-    public boolean onMenuOpened(int featureId, Menu menu) {
+    public boolean onMenuOpened(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(true);
         }
@@ -958,7 +959,7 @@
      * @see Activity#onMenuItemSelected(int, MenuItem)
      */
     @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
         return false;
     }
 
@@ -966,7 +967,7 @@
      * @see Activity#onPanelClosed(int, Menu)
      */
     @Override
-    public void onPanelClosed(int featureId, Menu menu) {
+    public void onPanelClosed(int featureId, @NonNull Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
             mActionBar.dispatchMenuVisibilityChanged(false);
         }
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 35999a2..1622c06 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -879,7 +879,7 @@
          * @return this object
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public Query orderBy(String column, int direction) {
             if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
                 throw new IllegalArgumentException("Invalid direction: " + direction);
@@ -1011,7 +1011,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setAccessFilename(boolean accessFilename) {
         mAccessFilename = accessFilename;
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 9f4157f..49917b4 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -264,7 +264,7 @@
  */
 @Deprecated
 public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final ArrayMap<String, Class<?>> sClassMap =
             new ArrayMap<String, Class<?>>();
 
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4f004d93..357420b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -112,6 +112,7 @@
 
     ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
     ParceledListSlice getSnoozedNotificationsFromListener(in INotificationListener token, int trim);
+    void clearRequestedListenerHints(in INotificationListener token);
     void requestHintsFromListener(in INotificationListener token, int hints);
     int getHintsFromListener(in INotificationListener token);
     void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3085fe5..b720df8 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -415,7 +416,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isDeviceLocked(int userId) {
         try {
             return mTrustManager.isDeviceLocked(userId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ddd9441..b827d01 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -111,7 +111,7 @@
     private String mDataDir;
     @UnsupportedAppUsage
     private String mLibDir;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private File mDataDirFile;
     private File mDeviceProtectedDataDirFile;
     private File mCredentialProtectedDataDirFile;
@@ -141,7 +141,7 @@
         = new ArrayMap<>();
     private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
         = new ArrayMap<>();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
         = new ArrayMap<>();
     private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
@@ -1358,7 +1358,7 @@
         final IIntentReceiver.Stub mIIntentReceiver;
         @UnsupportedAppUsage
         final BroadcastReceiver mReceiver;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final Context mContext;
         final Handler mActivityThread;
         final Instrumentation mInstrumentation;
@@ -1605,7 +1605,7 @@
         private final ServiceDispatcher.InnerConnection mIServiceConnection;
         @UnsupportedAppUsage
         private final ServiceConnection mConnection;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         private final Context mContext;
         private final Handler mActivityThread;
         private final ServiceConnectionLeaked mLocation;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9dca061..217225e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1417,7 +1417,7 @@
         public static final int SEMANTIC_ACTION_CALL = 10;
 
         private final Bundle mExtras;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
         private boolean mAllowGeneratedReplies = true;
@@ -3499,7 +3499,7 @@
 
         /**
          * Set the small icon, which will be used to represent the notification in the
-         * status bar and content view (unless overriden there by a
+         * status bar and content view (unless overridden there by a
          * {@link #setLargeIcon(Bitmap) large icon}).
          *
          * @param icon An Icon object to use.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b96b39d..9f819b9 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -841,9 +841,14 @@
             List<ZenModeConfig.ZenRule> rules = service.getZenRules();
             Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
             for (ZenModeConfig.ZenRule rule : rules) {
-                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
-                        rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                        rule.creationTime));
+                if (rule.zenPolicy == null) {
+                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                            rule.conditionId, zenModeToInterruptionFilter(rule.zenMode),
+                            rule.enabled, rule.creationTime));
+                } else {
+                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                            rule.conditionId, rule.zenPolicy, rule.enabled, rule.creationTime));
+                }
             }
             return ruleMap;
         } catch (RemoteException e) {
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index dbb6c3d..c0903b6 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -193,7 +194,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UiAutomation(Looper looper, IUiAutomationConnection connection) {
         if (looper == null) {
             throw new IllegalArgumentException("Looper cannot be null!");
@@ -210,7 +211,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void connect() {
         connect(0);
     }
@@ -282,7 +283,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void disconnect() {
         synchronized (mLock) {
             if (mIsConnecting) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 2a263d6..bebe79e 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1288,7 +1288,7 @@
      * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
             boolean allowBackup, @SetWallpaperFlags int which, int userId)
             throws IOException {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d1ecf1e..bd7a2dd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1183,14 +1183,6 @@
     public static final String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
 
     /**
-     * Constant to indicate the feature of mandatory backups. Used as argument to
-     * {@link #createAdminSupportIntent(String)}.
-     * @see #setMandatoryBackupTransport(ComponentName, ComponentName)
-     * @hide
-     */
-    public static final String POLICY_MANDATORY_BACKUPS = "policy_mandatory_backups";
-
-    /**
      * Constant to indicate the feature of suspending app. Use it as the value of
      * {@link #EXTRA_RESTRICTION}.
      * @hide
@@ -1200,8 +1192,7 @@
     /**
      * A String indicating a specific restricted feature. Can be a user restriction from the
      * {@link UserManager}, e.g. {@link UserManager#DISALLOW_ADJUST_VOLUME}, or one of the values
-     * {@link #POLICY_DISABLE_CAMERA}, {@link #POLICY_DISABLE_SCREEN_CAPTURE} or
-     * {@link #POLICY_MANDATORY_BACKUPS}.
+     * {@link #POLICY_DISABLE_CAMERA} or {@link #POLICY_DISABLE_SCREEN_CAPTURE}.
      * @see #createAdminSupportIntent(String)
      * @hide
      */
@@ -6919,7 +6910,7 @@
      * @param restriction Indicates for which feature the dialog should be displayed. Can be a
      *            user restriction from {@link UserManager}, e.g.
      *            {@link UserManager#DISALLOW_ADJUST_VOLUME}, or one of the constants
-     *            {@link #POLICY_DISABLE_CAMERA}, {@link #POLICY_DISABLE_SCREEN_CAPTURE}.
+     *            {@link #POLICY_DISABLE_CAMERA} or {@link #POLICY_DISABLE_SCREEN_CAPTURE}.
      * @return Intent An intent to be used to start the dialog-activity if the restriction is
      *            set by an admin, or null if the restriction does not exist or no admin set it.
      */
@@ -8917,55 +8908,6 @@
     }
 
     /**
-     * Makes backups mandatory and enforces the usage of the specified backup transport.
-     *
-     * <p>When a {@code null} backup transport is specified, backups are made optional again.
-     * <p>Only device owner can call this method.
-     * <p>If backups were disabled and a non-null backup transport {@link ComponentName} is
-     * specified, backups will be enabled.
-     * <p> If the backup service is disabled after the mandatory backup transport has been set, the
-     * mandatory backup transport is cleared.
-     *
-     * <p>NOTE: The method shouldn't be called on the main thread.
-     *
-     * @param admin admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param backupTransportComponent The backup transport layer to be used for mandatory backups.
-     * @return {@code true} if the backup transport was successfully set; {@code false} otherwise.
-     * @throws SecurityException if {@code admin} is not a device owner.
-     * @hide
-     */
-    @WorkerThread
-    public boolean setMandatoryBackupTransport(
-            @NonNull ComponentName admin,
-            @Nullable ComponentName backupTransportComponent) {
-        throwIfParentInstance("setMandatoryBackupTransport");
-        try {
-            return mService.setMandatoryBackupTransport(admin, backupTransportComponent);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Returns the backup transport which has to be used for backups if backups are mandatory or
-     * {@code null} if backups are not mandatory.
-     *
-     * @return a {@link ComponentName} of the backup transport layer to be used if backups are
-     *         mandatory or {@code null} if backups are not mandatory.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public ComponentName getMandatoryBackupTransport() {
-        throwIfParentInstance("getMandatoryBackupTransport");
-        try {
-            return mService.getMandatoryBackupTransport();
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-
-    /**
      * Called by a device owner to control the network logging feature.
      *
      * <p> Network logs contain DNS lookup and connect() library call events. The following library
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6a5f3de..35ea250 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -362,8 +362,6 @@
 
     void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
     boolean isBackupServiceEnabled(in ComponentName admin);
-    boolean setMandatoryBackupTransport(in ComponentName admin, in ComponentName backupTransportComponent);
-    ComponentName getMandatoryBackupTransport();
 
     void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
     boolean isNetworkLoggingEnabled(in ComponentName admin);
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 1c55d8a..3e20748 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -299,8 +299,7 @@
      *
      * @param transport ComponentName of the service hosting the transport. This is different from
      *                  the transport's name that is returned by {@link BackupTransport#name()}.
-     * @param listener A listener object to get a callback on the transport being selected. It may
-     *                 be {@code null}.
+     * @param listener A listener object to get a callback on the transport being selected.
      */
     void selectBackupTransportAsync(in ComponentName transport, ISelectBackupTransportCallback listener);
 
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 9baa16f..556ffa24 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -36,6 +36,7 @@
 import android.net.NetworkSpecifier;
 import android.net.Uri;
 import android.os.BaseBundle;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -311,7 +312,7 @@
     private final long initialBackoffMillis;
     private final int backoffPolicy;
     private final int priority;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int flags;
 
     /**
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 0994332..dbb00eb 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -25,6 +25,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -235,7 +236,7 @@
     @UnsupportedAppUsage
     private static final UsageEvents sEmptyResults = new UsageEvents();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Context mContext;
     @UnsupportedAppUsage
     private final IUsageStatsManager mService;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index d21f76d..466b9ce 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -571,7 +572,7 @@
      * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
         try {
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 78248ef..29d5a1c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -52,7 +53,7 @@
     private BluetoothDevice mDevice;
     @UnsupportedAppUsage
     private boolean mAutoConnect;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mAuthRetryState;
     private int mConnState;
     private final Object mStateLock = new Object();
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 9777b5c..3c3a01b 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -21,6 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 
 import java.util.List;
 
@@ -86,7 +87,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     int PAN = 5;
 
     /**
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index b55fe76..8691ed4 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -21,6 +21,7 @@
 import android.app.ActivityThread;
 import android.app.IActivityManager;
 import android.app.QueuedWork;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -71,22 +72,22 @@
         /** @hide */
         public static final int TYPE_UNREGISTERED = 2;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final int mType;
         @UnsupportedAppUsage
         final boolean mOrderedHint;
         @UnsupportedAppUsage
         final boolean mInitialStickyHint;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final IBinder mToken;
         @UnsupportedAppUsage
         final int mSendingUser;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         final int mFlags;
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         int mResultCode;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         String mResultData;
         @UnsupportedAppUsage
         Bundle mResultExtras;
@@ -96,7 +97,7 @@
         boolean mFinished;
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
                 boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
             mResultCode = resultCode;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 2b7ea66..089cf10 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -25,6 +25,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
@@ -198,7 +199,7 @@
         final CharSequence mText;
         final String mHtmlText;
         final Intent mIntent;
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         Uri mUri;
 
         /** @hide */
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index b96c8d3..428545d 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.NonNull;
 import android.content.res.Configuration;
 
 /**
@@ -44,7 +45,7 @@
      *
      * @param newConfig The new device configuration.
      */
-    void onConfigurationChanged(Configuration newConfig);
+    void onConfigurationChanged(@NonNull Configuration newConfig);
 
     /**
      * This is called when the overall system is running low on memory, and
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f5339ef..bd1e6a4 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -37,6 +37,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
@@ -163,7 +164,7 @@
      * in the test, which is available via {@link #getPathPermissions()}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public ContentProvider(
             Context context,
             String readPermission,
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 04be572..d315f49 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -24,6 +24,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.DeadObjectException;
@@ -73,7 +74,7 @@
     private final ContentResolver mContentResolver;
     @UnsupportedAppUsage
     private final IContentProvider mContentProvider;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mPackageName;
     private final boolean mStable;
 
diff --git a/core/java/android/content/ContentUris.java b/core/java/android/content/ContentUris.java
index dbe8a7c..fd7b372 100644
--- a/core/java/android/content/ContentUris.java
+++ b/core/java/android/content/ContentUris.java
@@ -18,6 +18,8 @@
 
 import android.net.Uri;
 
+import java.util.List;
+
 /**
 * Utility methods useful for working with {@link android.net.Uri} objects
 * that use the &quot;content&quot; (content://) scheme.
@@ -109,4 +111,30 @@
     public static Uri withAppendedId(Uri contentUri, long id) {
         return appendId(contentUri.buildUpon(), id).build();
     }
+
+    /**
+     * Removes any ID from the end of the path.
+     *
+     * @param contentUri that ends with an ID
+     * @return a new URI with the ID removed from the end of the path
+     * @throws IllegalArgumentException when the given URI has no ID to remove
+     *             from the end of the path
+     */
+    public static Uri removeId(Uri contentUri) {
+        // Verify that we have a valid ID to actually remove
+        final String last = contentUri.getLastPathSegment();
+        if (last == null) {
+            throw new IllegalArgumentException("No path segments to remove");
+        } else {
+            Long.parseLong(last);
+        }
+
+        final List<String> segments = contentUri.getPathSegments();
+        final Uri.Builder builder = contentUri.buildUpon();
+        builder.path(null);
+        for (int i = 0; i < segments.size() - 1; i++) {
+            builder.appendPath(segments.get(i));
+        }
+        return builder.build();
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ddd12a5..2ae3ae6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -327,6 +327,15 @@
     public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
 
     /**
+     * Flag for {@link #bindService}: If binding from something better than perceptible,
+     * still set the adjust below perceptible. This would be used for bound services that can
+     * afford to be evicted when under extreme memory pressure, but should be restarted as soon
+     * as possible.
+     * @hide
+     */
+    public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
+
+    /**
      * @hide Flag for {@link #bindService}: allows binding to a service provided
      * by an instant app. Note that the caller may not have access to the instant
      * app providing the service which is a violation of the instant app sandbox.
@@ -3407,7 +3416,7 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.app.NotificationManager} for controlling keyguard.
+     * {@link android.app.KeyguardManager} for controlling keyguard.
      *
      * @see #getSystemService(String)
      * @see android.app.KeyguardManager
@@ -3431,7 +3440,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final String COUNTRY_DETECTOR = "country_detector";
 
     /**
@@ -4792,6 +4801,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public Context createPackageContextAsUser(
             String packageName, @CreatePackageOptions int flags, UserHandle user)
             throws PackageManager.NameNotFoundException {
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index d814e67..044ed61 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -21,6 +21,7 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
@@ -80,7 +81,7 @@
             Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     static final String descriptor = "android.content.IContentProvider";
 
     @UnsupportedAppUsage
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 212e132..0dd6186 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
@@ -655,7 +656,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final boolean isVerified() {
         if ((mVerifyState & STATE_NEED_VERIFY_CHECKED) == STATE_NEED_VERIFY_CHECKED) {
             return ((mVerifyState & STATE_NEED_VERIFY) == STATE_NEED_VERIFY);
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 33395ec..bbdab04 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
@@ -403,7 +404,7 @@
     private static final String TAG_RESTRICTION = "restriction";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IRestrictionsManager mService;
 
     /**
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index fd12d7a..c18b282 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -18,6 +18,7 @@
 
 import android.accounts.Account;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,10 +34,10 @@
     @UnsupportedAppUsage
     private final Account mAccountToSync;
     /** Authority string that corresponds to a ContentProvider. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mAuthority;
     /** Bundle containing user info as well as sync settings. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Bundle mExtras;
     /** Don't allow this sync request on metered networks. */
     private final boolean mDisallowMetered;
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
new file mode 100644
index 0000000..69cc94f
--- /dev/null
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -0,0 +1,43 @@
+/*
+ * 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.content.pm;
+
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.PackageParser.Package;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+    @Override
+    public void updatePackage(Package pkg) {
+        // This was the default <= P and is maintained for backwards compatibility.
+        if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
+            prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 46877ca..44e652f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -42,6 +42,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -136,7 +137,7 @@
             "android.content.pm.extra.PIN_ITEM_REQUEST";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ILauncherApps mService;
     @UnsupportedAppUsage
     private final PackageManager mPm;
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index a16f81b..03eefed 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -53,6 +53,8 @@
                 "android.content.pm.OrgApacheHttpLegacyUpdater",
                 RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);
 
+        packageUpdaters.add(new AndroidHidlUpdater());
+
         // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
         // android.test.mock.
         packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 316ace1..8fab7bb 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager.InstallReason;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Build;
 import android.os.FileBridge;
 import android.os.Handler;
 import android.os.Looper;
@@ -960,6 +961,10 @@
          * If the installer is the device owner or the affiliated profile owner, there will be no
          * user intervention.
          *
+         * @param statusReceiver Called when the state of the session changes. Intents
+         *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
+         *                       individual status codes on how to handle them.
+         *
          * @throws SecurityException if streams opened through
          *             {@link #openWrite(String, long, long)} are still open.
          *
@@ -986,7 +991,9 @@
          * that new properties are added to the session with a new API revision. In this case the
          * callers need to be updated.
          *
-         * @param statusReceiver Callbacks called when the state of the session changes.
+         * @param statusReceiver Called when the state of the session changes. Intents
+         *                       sent to this receiver contain {@link #EXTRA_STATUS}. Refer to the
+         *                       individual status codes on how to handle them.
          *
          * @hide
          */
@@ -1091,7 +1098,7 @@
         public static final int UID_UNKNOWN = -1;
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int mode = MODE_INVALID;
         /** {@hide} */
         @UnsupportedAppUsage
@@ -1104,13 +1111,13 @@
         @UnsupportedAppUsage
         public long sizeBytes = -1;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appPackageName;
         /** {@hide} */
         @UnsupportedAppUsage
         public Bitmap appIcon;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appLabel;
         /** {@hide} */
         public long appIconLastModified = -1;
@@ -1435,40 +1442,40 @@
     public static class SessionInfo implements Parcelable {
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String installerPackageName;
         /** {@hide} */
         @UnsupportedAppUsage
         public String resolvedBaseCodePath;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public float progress;
         /** {@hide} */
         @UnsupportedAppUsage
         public boolean sealed;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public boolean active;
 
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int mode;
         /** {@hide} */
         public @InstallReason int installReason;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public long sizeBytes;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String appPackageName;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public Bitmap appIcon;
         /** {@hide} */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public CharSequence appLabel;
 
         /** {@hide} */
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 20e1454e..b5b4432 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -136,24 +136,6 @@
     public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
 
     /**
-     * Sets the SMS packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setSmsAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the dialer packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setDialerAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the sim call manager packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
-
-    /**
      * Sets the Use Open Wifi packages provider.
      * @param provider The packages provider.
      */
@@ -166,26 +148,28 @@
     public abstract void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider);
 
     /**
-     * Requests granting of the default permissions to the current default SMS app.
-     * @param packageName The default SMS package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default dialer changed
+     *
+     * @param packageName the new dialer package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId);
+    public void onDefaultDialerAppChanged(String packageName, int userId) {}
 
     /**
-     * Requests granting of the default permissions to the current default dialer app.
-     * @param packageName The default dialer package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default SMS handler changed
+     *
+     * @param packageName the new sms package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId);
+    public void onDefaultSmsAppChanged(String packageName, int userId) {}
 
     /**
-     * Requests granting of the default permissions to the current default sim call manager.
-     * @param packageName The default sim call manager package name.
-     * @param userId The user for which to grant the permissions.
+     * Called when the package for the default sim call manager changed
+     *
+     * @param packageName the new sms package
+     * @param userId user for which the change was made
      */
-    public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName,
-            int userId);
+    public void onDefaultSimCallManagerAppChanged(String packageName, int userId) {}
 
     /**
      * Requests granting of the default permissions to the current default Use Open Wifi app.
@@ -446,8 +430,8 @@
          *
          * @param packageName The package to check for
          * @param uid the uid in which the package is running
-         * @return {@link USER_TRUSTED} if the user has trusted the package, {@link USER_BLOCKED}
-         * if user has blocked requests from the package, {@link USER_DEFAULT} if the user response
+         * @return {@link #USER_TRUSTED} if the user has trusted the package, {@link #USER_BLOCKED}
+         * if user has blocked requests from the package, {@link #USER_DEFAULT} if the user response
          * is not yet available
          */
         int getPackageTrustedToInstallApps(String packageName, int uid);
@@ -561,7 +545,7 @@
     /**
      * Returns a list without a change observer.
      *
-     * {@see #getPackageList(PackageListObserver)}
+     * @see #getPackageList(PackageListObserver)
      */
     public @NonNull PackageList getPackageList() {
         return getPackageList(null);
@@ -590,7 +574,16 @@
     /**
      * Returns a package object for the disabled system package name.
      */
-    public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName);
+    public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
+            @NonNull String packageName);
+
+    /**
+     * Returns the package name for the disabled system package.
+     *
+     * This is equivalent to
+     * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
+     */
+    public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
 
     /**
      * Returns whether or not the component is the resolver activity.
@@ -619,7 +612,7 @@
      * Access may be limited based upon whether the calling or target applications
      * are instant applications.
      *
-     * @see #canAccessInstantApps(int)
+     * @see #canAccessInstantApps
      */
     public abstract boolean filterAppAccess(
             @Nullable PackageParser.Package pkg, int callingUid, int userId);
@@ -635,6 +628,9 @@
     public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
             @NonNull String packageName, int flagMask, int flagValues, int userId);
 
+    /** Returns whether the given package was signed by the platform */
+    public abstract boolean isPlatformSigned(String pkg);
+
     /**
      * Returns true if it's still safe to restore data backed up from this app's version
      * that was signed with restoringFromSigHash.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6d49362..03a3d1f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1902,7 +1902,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
             String[] outError) throws XmlPullParserException, IOException {
         final String splitName;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 2eef165..dccc524 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -72,7 +73,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
             new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
         public ParceledListSlice createFromParcel(Parcel in) {
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 83e8663..387d29e8 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,6 +22,10 @@
  */
 public class SharedLibraryNames {
 
+    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+
+    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+
     static final String ANDROID_TEST_BASE = "android.test.base";
 
     static final String ANDROID_TEST_MOCK = "android.test.mock";
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 546c213..ec2e2fd 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1243,7 +1244,7 @@
      * @hide
      */
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 60ac1f0..2d59003 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.graphics.drawable.AdaptiveIconDrawable;
+import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -55,7 +56,7 @@
     private static final String TAG = "ShortcutManager";
 
     private final Context mContext;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IShortcutService mService;
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 43e1612..88b1c88 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1129,10 +1129,8 @@
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *         not exist or is not a floating-point value.
-     * @hide Pending API council approval.
      */
-    @UnsupportedAppUsage
-    public float getFloat(int id) {
+    public float getFloat(@DimenRes int id) {
         final TypedValue value = obtainTempTypedValue();
         try {
             mResourcesImpl.getValue(id, value, true);
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index c6c2aa5..8bcaa45 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -19,6 +19,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
@@ -79,7 +80,7 @@
     private final DataSetObservable mDataSetObservable = new DataSetObservable();
     private final ContentObservable mContentObservable = new ContentObservable();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Bundle mExtras = Bundle.EMPTY;
 
     /* -------------------------------------------------------- */
diff --git a/core/java/android/database/sqlite/SQLiteCustomFunction.java b/core/java/android/database/sqlite/SQLiteCustomFunction.java
index ec20458..41b78d3 100644
--- a/core/java/android/database/sqlite/SQLiteCustomFunction.java
+++ b/core/java/android/database/sqlite/SQLiteCustomFunction.java
@@ -17,6 +17,7 @@
 package android.database.sqlite;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 
 /**
  * Describes a custom SQL function.
@@ -24,7 +25,7 @@
  * @hide
  */
 public final class SQLiteCustomFunction {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final String name;
     @UnsupportedAppUsage
     public final int numArgs;
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 1377806..19c6745 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -49,7 +49,7 @@
  * <p class="note"><strong>Note:</strong> this class assumes
  * monotonically increasing version numbers for upgrades.</p>
  */
-public abstract class SQLiteOpenHelper {
+public abstract class SQLiteOpenHelper implements AutoCloseable {
     private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
 
     private final Context mContext;
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index b705ebb..4fce2d7 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -34,6 +34,7 @@
 
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
@@ -50,6 +51,8 @@
             Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
 
     private Map<String, String> mProjectionMap = null;
+    private List<Pattern> mProjectionGreylist = null;
+
     @UnsupportedAppUsage
     private String mTables = "";
     @UnsupportedAppUsage
@@ -164,6 +167,17 @@
     }
 
     /**
+     * Sets a projection greylist of columns that will be allowed through, even
+     * when {@link #setStrict(boolean)} is enabled. This provides a way for
+     * abusive custom columns like {@code COUNT(*)} to continue working.
+     *
+     * @hide
+     */
+    public void setProjectionGreylist(List<Pattern> projectionGreylist) {
+        mProjectionGreylist = projectionGreylist;
+    }
+
+    /**
      * Sets the cursor factory to be used for the query.  You can use
      * one factory for all queries on a database but it is normally
      * easier to specify the factory when doing this query.
@@ -809,6 +823,24 @@
                         continue;
                     }
 
+                    // If greylist is configured, we might be willing to let
+                    // this custom column bypass our strict checks.
+                    if (mProjectionGreylist != null) {
+                        boolean match = false;
+                        for (Pattern p : mProjectionGreylist) {
+                            if (p.matcher(userColumn).matches()) {
+                                match = true;
+                                break;
+                            }
+                        }
+
+                        if (match) {
+                            Log.w(TAG, "Allowing abusive custom column: " + userColumn);
+                            projection[i] = userColumn;
+                            continue;
+                        }
+                    }
+
                     throw new IllegalArgumentException("Invalid column "
                             + projectionIn[i]);
                 }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8e96f56..ac863b2 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -31,6 +31,7 @@
 import android.graphics.SurfaceTexture;
 import android.media.AudioAttributes;
 import android.media.IAudioService;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -165,7 +166,7 @@
     private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
     private static final int CAMERA_MSG_FOCUS_MOVE       = 0x800;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private long mNativeContext; // accessed by native methods
     private EventHandler mEventHandler;
     private ShutterCallback mShutterCallback;
@@ -721,7 +722,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public native final void setPreviewSurface(Surface surface) throws IOException;
 
     /**
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index c17aabb..d2c0e7b 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -20,6 +20,7 @@
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -184,7 +185,7 @@
      * Private use only. See {@link #create(int, int, int, int, long)}. May also be
      * called from JNI using an already allocated native <code>HardwareBuffer</code>.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private HardwareBuffer(long nativeObject) {
         mNativeObject = nativeObject;
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 35584ae..46e66e0 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -188,6 +188,7 @@
     @UnsupportedAppUsage
     private final CameraMetadataNative mProperties;
     private List<CameraCharacteristics.Key<?>> mKeys;
+    private List<CameraCharacteristics.Key<?>> mKeysNeedingPermission;
     private List<CaptureRequest.Key<?>> mAvailableRequestKeys;
     private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
     private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
@@ -268,11 +269,50 @@
         }
 
         mKeys = Collections.unmodifiableList(
-                getKeys(getClass(), getKeyClass(), this, filterTags));
+                getKeys(getClass(), getKeyClass(), this, filterTags, true));
         return mKeys;
     }
 
     /**
+     * <p>Returns a subset of the list returned by {@link #getKeys} with all keys that
+     * require camera clients to obtain the {@link android.Manifest.permission#CAMERA} permission.
+     * </p>
+     *
+     * <p>If an application calls {@link CameraManager#getCameraCharacteristics} without holding the
+     * {@link android.Manifest.permission#CAMERA} permission,
+     * all keys in this list will not be available, and calling {@link #get} will
+     * return null for those keys. If the application obtains the
+     * {@link android.Manifest.permission#CAMERA} permission, then the
+     * CameraCharacteristics from a call to a subsequent
+     * {@link CameraManager#getCameraCharacteristics} will have the keys available.</p>
+     *
+     * <p>The list returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+     *
+     * @return List of camera characteristic keys that require the
+     *         {@link android.Manifest.permission#CAMERA} permission. The list can be null in case
+     *         there are no currently present keys that need additional permission.
+     */
+    public List<Key<?>> getKeysNeedingPermission() {
+        if (mKeysNeedingPermission == null) {
+            Object crKey = CameraCharacteristics.Key.class;
+            Class<CameraCharacteristics.Key<?>> crKeyTyped =
+                (Class<CameraCharacteristics.Key<?>>)crKey;
+
+            int[] filterTags = get(REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION);
+            if (filterTags == null) {
+                return null;
+            }
+            mKeysNeedingPermission =
+                getAvailableKeyList(CameraCharacteristics.class, crKeyTyped, filterTags,
+                        /*includeSynthetic*/ false);
+        }
+        return mKeysNeedingPermission;
+    }
+
+    /**
      * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
      * camera device can pass as part of the capture session initialization.</p>
      *
@@ -328,17 +368,18 @@
                 return null;
             }
             mAvailableSessionKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ false);
         }
         return mAvailableSessionKeys;
     }
 
     /**
      * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that can
-     * be overriden for physical devices backing a logical multi-camera.</p>
+     * be overridden for physical devices backing a logical multi-camera.</p>
      *
      * <p>This is a subset of android.request.availableRequestKeys which contains a list
-     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
      * The respective value of such request key can be obtained by calling
      * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
      * individual physical device requests must be built via
@@ -353,7 +394,7 @@
      *
      * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
      *
-     * @return List of keys that can be overriden in individual physical device requests.
+     * @return List of keys that can be overridden in individual physical device requests.
      * In case the camera device doesn't support such keys the list can be null.
      */
     @SuppressWarnings({"unchecked"})
@@ -367,7 +408,8 @@
                 return null;
             }
             mAvailablePhysicalRequestKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ false);
         }
         return mAvailablePhysicalRequestKeys;
     }
@@ -399,7 +441,8 @@
                         + "in the characteristics");
             }
             mAvailableRequestKeys =
-                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags);
+                    getAvailableKeyList(CaptureRequest.class, crKeyTyped, filterTags,
+                            /*includeSynthetic*/ true);
         }
         return mAvailableRequestKeys;
     }
@@ -430,7 +473,8 @@
                 throw new AssertionError("android.request.availableResultKeys must be non-null "
                         + "in the characteristics");
             }
-            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags);
+            mAvailableResultKeys = getAvailableKeyList(CaptureResult.class, crKeyTyped, filterTags,
+                    /*includeSynthetic*/ true);
         }
         return mAvailableResultKeys;
     }
@@ -445,13 +489,16 @@
      *
      * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
      * @param keyClass The class of the metadata key, e.g. CaptureRequest.Key.class
+     * @param filterTags An array of tags to be used for filtering
+     * @param includeSynthetic Include public syntethic tag by default.
      *
      * @return List of keys supported by this CameraDevice for metadataClass.
      *
      * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
      */
     private <TKey> List<TKey>
-    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags) {
+    getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags,
+            boolean includeSynthetic) {
 
         if (metadataClass.equals(CameraMetadata.class)) {
             throw new AssertionError(
@@ -462,7 +509,7 @@
         }
 
         List<TKey> staticKeyList = getKeys(
-                metadataClass, keyClass, /*instance*/null, filterTags);
+                metadataClass, keyClass, /*instance*/null, filterTags, includeSynthetic);
         return Collections.unmodifiableList(staticKeyList);
     }
 
@@ -474,6 +521,13 @@
      * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability. If the camera device
      * doesn't have the capability, the return value will be an empty set. </p>
      *
+     * <p>Prior to API level 29, all returned IDs are guaranteed to be returned by {@link
+     * CameraManager#getCameraIdList}, and can be opened directly by
+     * {@link CameraManager#openCamera}. Starting from API level 29, for each of the returned ID,
+     * if it's also returned by {@link CameraManager#getCameraIdList}, it can be used as a
+     * standalone camera by {@link CameraManager#openCamera}. Otherwise, the camera ID can only be
+     * used as part of the current logical camera.</p>
+     *
      * <p>The set returned is not modifiable, so any attempts to modify it will throw
      * a {@code UnsupportedOperationException}.</p>
      *
@@ -1103,6 +1157,7 @@
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1124,6 +1179,7 @@
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
@@ -1238,6 +1294,7 @@
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_ROTATION =
@@ -1273,6 +1330,7 @@
      * with PRIMARY_CAMERA.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -1344,6 +1402,7 @@
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
      * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -1387,6 +1446,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @deprecated
@@ -1411,6 +1471,7 @@
      *   <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
      * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
@@ -1452,6 +1513,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
@@ -1860,10 +1922,10 @@
             new Key<int[]>("android.request.availableSessionKeys", int[].class);
 
     /**
-     * <p>A subset of the available request keys that can be overriden for
+     * <p>A subset of the available request keys that can be overridden for
      * physical devices backing a logical multi-camera.</p>
      * <p>This is a subset of android.request.availableRequestKeys which contains a list
-     * of keys that can be overriden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
+     * of keys that can be overridden using {@link CaptureRequest.Builder#setPhysicalCameraKey }.
      * The respective value of such request key can be obtained by calling
      * {@link CaptureRequest.Builder#getPhysicalCameraKey }. Capture requests that contain
      * individual physical device requests must be built via
@@ -1880,6 +1942,21 @@
             new Key<int[]>("android.request.availablePhysicalCameraRequestKeys", int[].class);
 
     /**
+     * <p>A list of camera characteristics keys that are only available
+     * in case the camera client has camera permission.</p>
+     * <p>The entry contains a subset of
+     * {@link android.hardware.camera2.CameraCharacteristics#getKeys } that require camera clients
+     * to acquire the {@link android.Manifest.permission#CAMERA } permission before calling
+     * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }. If the
+     * permission is not held by the camera client, then the values of the repsective properties
+     * will not be present in {@link android.hardware.camera2.CameraCharacteristics }.</p>
+     * <p>This key is available on all devices.</p>
+     * @hide
+     */
+    public static final Key<int[]> REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION =
+            new Key<int[]>("android.request.characteristicKeysNeedingPermission", int[].class);
+
+    /**
      * <p>The list of image formats that are supported by this
      * camera device for output streams.</p>
      * <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
@@ -2703,6 +2780,7 @@
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN ISO_STUDIO_TUNGSTEN}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1
      * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM1
@@ -2744,6 +2822,7 @@
      * <p><b>Range of valid values:</b><br>
      * Any value listed in {@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM2
      * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM2
@@ -2766,6 +2845,7 @@
      * space under the first reference illuminant
      * ({@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}).</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2788,6 +2868,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -2811,6 +2892,7 @@
      * match the standard white point for the first reference illuminant
      * (i.e. no chromatic adaptation will be applied by this transform).</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2836,6 +2918,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
@@ -2857,6 +2940,7 @@
      * illuminant in the reference sensor colorspace is mapped to D50 in the
      * CIE XYZ colorspace.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
      */
@@ -2880,6 +2964,7 @@
      * <p>This matrix will only be present if the second reference
      * illuminant is present.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      */
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7ebe0f9..44d7364 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -34,7 +34,6 @@
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
@@ -45,7 +44,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.RejectedExecutionException;
@@ -97,6 +95,9 @@
      * identifiers, while removable cameras have a unique identifier for each
      * individual device, even if they are the same model.</p>
      *
+     * <p>This list doesn't contain physical cameras that can only used as part of a logical
+     * multi-camera device.</p>
+     *
      * @return The list of currently connected camera devices.
      */
     @NonNull
@@ -234,7 +235,13 @@
      * <p>Query the capabilities of a camera device. These capabilities are
      * immutable for a given camera.</p>
      *
-     * @param cameraId The id of the camera device to query
+     * <p>From API level 29, this function can also be used to query the capabilities of physical
+     * cameras that can only be used as part of logical multi-camera. These cameras cannot not be
+     * opened directly via {@link #openCamera}</p>
+     *
+     * @param cameraId The id of the camera device to query. This could be either a standalone
+     * camera ID which can be directly opened by {@link #openCamera}, or a physical camera ID that
+     * can only used as part of a logical multi-camera.
      * @return The properties of the given camera
      *
      * @throws IllegalArgumentException if the cameraId does not match any
@@ -262,7 +269,9 @@
                         "Camera service is currently unavailable");
             }
             try {
-                if (!supportsCamera2ApiLocked(cameraId)) {
+                // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
+                // exception in case cameraId is a hidden physical camera.
+                if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
                     // Legacy backwards compatibility path; build static info from the camera
                     // parameters
                     int id = Integer.parseInt(cameraId);
@@ -454,7 +463,7 @@
      *
      * @throws IllegalArgumentException if cameraId or the callback was null,
      * or the cameraId does not match any currently or previously available
-     * camera device.
+     * camera device returned by {@link #getCameraIdList}.
      *
      * @throws SecurityException if the application does not have permission to
      * access the camera
@@ -778,6 +787,29 @@
     }
 
     /**
+     * Queries the camera service if a cameraId is a hidden physical camera that belongs to a
+     * logical camera device.
+     *
+     * A hidden physical camera is a camera that cannot be opened by the application. But it
+     * can be used as part of a logical camera.
+     *
+     * @param cameraId a non-{@code null} camera identifier
+     * @return {@code true} if cameraId is a hidden physical camera device
+     */
+    private boolean isHiddenPhysicalCamera(String cameraId) {
+        try {
+            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+            // If no camera service, no support
+            if (cameraService == null) return false;
+
+            return cameraService.isHiddenPhysicalCamera(cameraId);
+        } catch (RemoteException e) {
+            // Camera service is now down, no support for any API level
+        }
+        return false;
+    }
+
+    /**
      * A per-process global camera manager instance, to retain a connection to the camera service,
      * and to distribute camera availability notices to API-registered callbacks
      */
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index caa99d5..486b054 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -116,7 +116,8 @@
     public List<TKey> getKeys() {
         Class<CameraMetadata<TKey>> thisClass = (Class<CameraMetadata<TKey>>) getClass();
         return Collections.unmodifiableList(
-                getKeys(thisClass, getKeyClass(), this, /*filterTags*/null));
+                getKeys(thisClass, getKeyClass(), this, /*filterTags*/null,
+                    /*includeSynthetic*/ true));
     }
 
     /**
@@ -131,13 +132,14 @@
      * Optionally, if {@code filterTags} is not {@code null}, then filter out any keys
      * whose native {@code tag} is not in {@code filterTags}. The {@code filterTags} array will be
      * sorted as a side effect.
+     * {@code includeSynthetic} Includes public syntenthic fields by default.
      * </p>
      */
      /*package*/ @SuppressWarnings("unchecked")
     <TKey> ArrayList<TKey> getKeys(
              Class<?> type, Class<TKey> keyClass,
              CameraMetadata<TKey> instance,
-             int[] filterTags) {
+             int[] filterTags, boolean includeSynthetic) {
 
         if (DEBUG) Log.v(TAG, "getKeysStatic for " + type);
 
@@ -168,7 +170,7 @@
                 }
 
                 if (instance == null || instance.getProtected(key) != null) {
-                    if (shouldKeyBeAdded(key, field, filterTags)) {
+                    if (shouldKeyBeAdded(key, field, filterTags, includeSynthetic)) {
                         keyList.add(key);
 
                         if (DEBUG) {
@@ -215,7 +217,8 @@
     }
 
     @SuppressWarnings("rawtypes")
-    private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags) {
+    private static <TKey> boolean shouldKeyBeAdded(TKey key, Field field, int[] filterTags,
+            boolean includeSynthetic) {
         if (key == null) {
             throw new NullPointerException("key must not be null");
         }
@@ -249,8 +252,7 @@
         if (field.getAnnotation(SyntheticKey.class) != null) {
             // This key is synthetic, so calling #getTag will throw IAE
 
-            // TODO: don't just assume all public+synthetic keys are always available
-            return true;
+            return includeSynthetic;
         }
 
         /*
@@ -811,8 +813,14 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING = 10;
 
     /**
-     * <p>The camera device is a logical camera backed by two or more physical cameras that are
-     * also exposed to the application.</p>
+     * <p>The camera device is a logical camera backed by two or more physical cameras. In
+     * API level 28, the physical cameras must also be exposed to the application via
+     * {@link android.hardware.camera2.CameraManager#getCameraIdList }. Starting from API
+     * level 29, some or all physical cameras may not be independently exposed to the
+     * application, in which case the physical camera IDs will not be available in
+     * {@link android.hardware.camera2.CameraManager#getCameraIdList }. But the application
+     * can still query the physical cameras' characteristics by calling
+     * {@link android.hardware.camera2.CameraManager#getCameraCharacteristics }.</p>
      * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
      * camera in the system. For an application that switches between front and back cameras,
      * the recommendation is to switch between the first rear camera and the first front
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3c6c11d..a7e185c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2841,6 +2841,7 @@
      * <p><b>Units</b>:
      * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_ROTATION =
@@ -2876,6 +2877,7 @@
      * with PRIMARY_CAMERA.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
@@ -2947,6 +2949,7 @@
      * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}
      * coordinate system.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
@@ -2990,6 +2993,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @deprecated
@@ -3036,6 +3040,7 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6ca5f0c..bfb7c58 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -65,7 +66,7 @@
 
     private static InputManager sInstance;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final IInputManager mIm;
 
     // Guarded by mInputDevicesLock
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index ae0855a..4111941 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -385,7 +386,7 @@
     /**
      * {@hide}
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UsbManager(Context context, IUsbManager service) {
         mContext = context;
         mService = service;
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 4080ee6..1030694 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -160,11 +160,10 @@
                 args.recycle();
                 return;
             }
-
             case DO_INITIALIZE_INTERNAL: {
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
-                    inputMethod.initializeInternal((IBinder) args.arg1,
+                    inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
                             (IInputMethodPrivilegedOperations) args.arg2);
                 } finally {
                     args.recycle();
@@ -253,9 +252,10 @@
 
     @BinderThread
     @Override
-    public void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps) {
+    public void initializeInternal(IBinder token, int displayId,
+            IInputMethodPrivilegedOperations privOps) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageOO(DO_INITIALIZE_INTERNAL, token, privOps));
+                mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2d12b86..34fa5b6 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -16,6 +16,7 @@
 
 package android.inputmethodservice;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -461,10 +462,11 @@
          */
         @MainThread
         @Override
-        public final void initializeInternal(IBinder token,
+        public final void initializeInternal(IBinder token, int displayId,
                 IInputMethodPrivilegedOperations privilegedOperations) {
             mPrivOps.set(privilegedOperations);
             mImm.registerInputMethodPrivOps(token, mPrivOps);
+            updateInputMethodDisplay(displayId);
             attachToken(token);
         }
 
@@ -484,6 +486,22 @@
 
         /**
          * {@inheritDoc}
+         * @hide
+         */
+        @MainThread
+        @Override
+        public void updateInputMethodDisplay(int displayId) {
+            // Update display for adding IME window to the right display.
+            if (displayId != DEFAULT_DISPLAY) {
+                // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
+                // for update resources & configuration correctly when show soft input
+                // in non-default display.
+                updateDisplay(displayId);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
          *
          * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
          */
@@ -930,6 +948,9 @@
         // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
         // we continue to use the same size of the inset or update it
         mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
+        // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
+        // for update resources & configuration correctly when show soft input
+        // in non-default display.
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index ec5f050..51d33b2 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -25,6 +25,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.TypedValue;
@@ -627,7 +628,7 @@
         rows.add(row);
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     final void resize(int newWidth, int newHeight) {
         int numRows = rows.size();
         for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index fd1e5f2..12b6f9e 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -904,7 +905,7 @@
      *         specifier. See {@link #setNetworkSpecifier}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public NetworkSpecifier getNetworkSpecifier() {
         return mNetworkSpecifier;
     }
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 010d72f..9c836c3 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -211,7 +211,7 @@
      * Called for every request every time a new NetworkRequest is seen
      * and whenever the filterScore or filterNetworkCapabilities change.
      *
-     * acceptRequest can be overriden to provide complex filter behavior
+     * acceptRequest can be overridden to provide complex filter behavior
      * for the incoming requests
      *
      * For output, this class will call {@link #needNetworkFor} and
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 9ce2a5b..be2f955 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -35,7 +35,7 @@
     public abstract boolean satisfiedBy(NetworkSpecifier other);
 
     /**
-     * Optional method which can be overriden by concrete implementations of NetworkSpecifier to
+     * Optional method which can be overridden by concrete implementations of NetworkSpecifier to
      * check a self-reported UID. A concrete implementation may contain a UID which would be self-
      * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
      * function is called by ConnectivityService and is passed the actual UID of the caller -
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index c545ee2..97fb3fb 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Slog;
@@ -34,7 +35,7 @@
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
     public final NetworkCapabilities networkCapabilities;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Network network;
     public final String subscriberId;
     public final String networkId;
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 31494d9..abc1cac 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.SystemProperties;
 import android.util.Log;
 
@@ -87,7 +88,7 @@
  * requires root access.
  */
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final String TAG = "SSLCertificateSocketFactory";
 
     @UnsupportedAppUsage
@@ -384,7 +385,7 @@
      * @throws IllegalArgumentException if the socket was not created by this factory.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public byte[] getAlpnSelectedProtocol(Socket socket) {
         return castToOpenSSLSocket(socket).getAlpnSelectedProtocol();
     }
@@ -410,7 +411,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setChannelIdPrivateKey(PrivateKey privateKey) {
         mChannelIdPrivateKey = privateKey;
     }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 9bcc600..40465ce 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -197,7 +197,7 @@
      *
      * <p>Example: "//www.google.com/search?q=android"
      *
-     * @return the decoded scheme-specific-part
+     * @return the encoded scheme-specific-part
      */
     public abstract String getEncodedSchemeSpecificPart();
 
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 71199c9..030066e 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.os.Build;
 
 /**
  * High level manager used to obtain an instance of an {@link NfcAdapter}.
@@ -45,7 +46,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public NfcManager(Context context) {
         NfcAdapter adapter;
         context = context.getApplicationContext();
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 0fef78d..3d4c00c 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -1601,12 +1601,13 @@
     private void readFromParcelInner(Parcel parcel, int length) {
         if (length < 0) {
             throw new RuntimeException("Bad length in parcel: " + length);
-
         } else if (length == 0) {
             // Empty Bundle or end of data.
             mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
             mParcelledByNative = false;
             return;
+        } else if (length % 4 != 0) {
+            throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
         }
 
         final int magic = parcel.readInt();
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 347f60f..3c43fd18 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
@@ -165,6 +166,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getOemDirectory() {
         return DIR_OEM_ROOT;
     }
@@ -175,6 +177,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getOdmDirectory() {
         return DIR_ODM_ROOT;
     }
@@ -184,6 +187,7 @@
      * software that should persist across simple reflashing of the "system" partition.
      * @hide
      */
+    @SystemApi
     public static File getVendorDirectory() {
         return DIR_VENDOR_ROOT;
     }
@@ -194,6 +198,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getProductDirectory() {
         return DIR_PRODUCT_ROOT;
     }
@@ -204,6 +209,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static File getProductServicesDirectory() {
         return DIR_PRODUCT_SERVICES_ROOT;
     }
@@ -1063,7 +1069,6 @@
         return cur;
     }
 
-
     /**
      * If the given path exists on emulated external storage, return the
      * translated backing path hosted on internal storage. This bypasses any
@@ -1074,8 +1079,10 @@
      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
      * permission.
      *
+     * @deprecated disabled now that FUSE has been replaced by sdcardfs
      * @hide
      */
+    @Deprecated
     public static File maybeTranslateEmulatedPathToInternal(File path) {
         return StorageManager.maybeTranslateEmulatedPathToInternal(path);
     }
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1c8029c..a9cb0d9 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,18 @@
 
 package android.os;
 
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
 import static android.system.OsConstants.SPLICE_F_MORE;
 import static android.system.OsConstants.SPLICE_F_MOVE;
 import static android.system.OsConstants.S_ISFIFO;
@@ -1061,8 +1073,13 @@
                 mimeTypeFromExt = ContentResolver.MIME_TYPE_DEFAULT;
             }
 
-            final String extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(
-                    mimeType);
+            final String extFromMimeType;
+            if (ContentResolver.MIME_TYPE_DEFAULT.equals(mimeType)) {
+                extFromMimeType = null;
+            } else {
+                extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
+            }
+
             if (Objects.equals(mimeType, mimeTypeFromExt) || Objects.equals(ext, extFromMimeType)) {
                 // Extension maps back to requested MIME type; allow it
             } else {
@@ -1180,6 +1197,96 @@
     }
 
     /** {@hide} */
+    public static int translateModeStringToPosix(String mode) {
+        int res = 0;
+        if (mode.startsWith("rw")) {
+            res |= O_RDWR | O_CREAT;
+        } else if (mode.startsWith("w")) {
+            res |= O_WRONLY | O_CREAT;
+        } else if (mode.startsWith("r")) {
+            res |= O_RDONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if (mode.indexOf('t') != -1) {
+            res |= O_TRUNC;
+        }
+        if (mode.indexOf('a') != -1) {
+            res |= O_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static String translateModePosixToString(int mode) {
+        String res = "";
+        if ((mode & O_RDWR) == O_RDWR) {
+            res += "rw";
+        } else if ((mode & O_WRONLY) == O_WRONLY) {
+            res += "w";
+        } else if ((mode & O_RDONLY) == O_RDONLY) {
+            res += "r";
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & O_TRUNC) == O_TRUNC) {
+            res += "t";
+        }
+        if ((mode & O_APPEND) == O_APPEND) {
+            res += "a";
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static int translateModePosixToPfd(int mode) {
+        int res = 0;
+        if ((mode & O_RDWR) == O_RDWR) {
+            res |= MODE_READ_WRITE;
+        } else if ((mode & O_WRONLY) == O_WRONLY) {
+            res |= MODE_WRITE_ONLY;
+        } else if ((mode & O_RDONLY) == O_RDONLY) {
+            res |= MODE_READ_ONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & O_CREAT) == O_CREAT) {
+            res |= MODE_CREATE;
+        }
+        if ((mode & O_TRUNC) == O_TRUNC) {
+            res |= MODE_TRUNCATE;
+        }
+        if ((mode & O_APPEND) == O_APPEND) {
+            res |= MODE_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
+    public static int translateModePfdToPosix(int mode) {
+        int res = 0;
+        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+            res |= O_RDWR;
+        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
+            res |= O_WRONLY;
+        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {
+            res |= O_RDONLY;
+        } else {
+            throw new IllegalArgumentException("Bad mode: " + mode);
+        }
+        if ((mode & MODE_CREATE) == MODE_CREATE) {
+            res |= O_CREAT;
+        }
+        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {
+            res |= O_TRUNC;
+        }
+        if ((mode & MODE_APPEND) == MODE_APPEND) {
+            res |= O_APPEND;
+        }
+        return res;
+    }
+
+    /** {@hide} */
     @VisibleForTesting
     public static class MemoryPipe extends Thread implements AutoCloseable {
         private final FileDescriptor[] pipe;
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 9b202f2..e03af9d 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -33,7 +33,7 @@
  * them as they come out of the message queue.
  * 
  * <p>There are two main uses for a Handler: (1) to schedule messages and
- * runnables to be executed as some point in the future; and (2) to enqueue
+ * 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
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index c9edc53..a54c589 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -559,28 +559,7 @@
      * @throws IllegalArgumentException if the given string does not match a known file mode.
      */
     public static int parseMode(String mode) {
-        final int modeBits;
-        if ("r".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
-        } else if ("w".equals(mode) || "wt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else if ("wa".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_APPEND;
-        } else if ("rw".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE;
-        } else if ("rwt".equals(mode)) {
-            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
-                    | ParcelFileDescriptor.MODE_CREATE
-                    | ParcelFileDescriptor.MODE_TRUNCATE;
-        } else {
-            throw new IllegalArgumentException("Bad mode '" + mode + "'");
-        }
-        return modeBits;
+        return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
     }
 
     /**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 995156a..4fe2d58 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -38,12 +38,16 @@
     public static final @UserIdInt int USER_ALL = -1;
 
     /** @hide A user handle to indicate all users on the device */
+    @SystemApi
+    @TestApi
     public static final UserHandle ALL = new UserHandle(USER_ALL);
 
     /** @hide A user id to indicate the currently active user */
     public static final @UserIdInt int USER_CURRENT = -2;
 
     /** @hide A user handle to indicate the current user of the device */
+    @SystemApi
+    @TestApi
     public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
 
     /** @hide A user id to indicate that we would like to send to the current
@@ -83,6 +87,7 @@
     public static final int USER_SERIAL_SYSTEM = 0;
 
     /** @hide A user handle to indicate the "system" user of the device */
+    @SystemApi
     @TestApi
     public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
 
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index f303674..71eda19 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -20,6 +20,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -65,7 +66,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static SystemHealthManager from(Context context) {
         return (SystemHealthManager)context.getSystemService(Context.SYSTEM_HEALTH_SERVICE);
     }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8d5017b..50ca4ab 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1521,7 +1521,11 @@
         return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
     }
 
-    /** {@hide} */
+    /**
+     * @deprecated disabled now that FUSE has been replaced by sdcardfs
+     * @hide
+     */
+    @Deprecated
     public static File maybeTranslateEmulatedPathToInternal(File path) {
         // Disabled now that FUSE has been replaced by sdcardfs
         return path;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index deff693..5bef7ee 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -249,7 +250,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UserHandle getOwner() {
         return mOwner;
     }
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 98b69a8..2387657 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -27,6 +27,7 @@
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1167,7 +1168,7 @@
      * @return True if the Preference handled the key. Returns false by default.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         return false;
     }
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index c76c8d3..dfee1af 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -68,7 +69,7 @@
      * Fragment that owns this instance.
      */
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private PreferenceFragment mFragment;
 
     /**
@@ -201,7 +202,7 @@
     /**
      * Sets the owning preference fragment
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     void setFragment(PreferenceFragment fragment) {
         mFragment = fragment;
     }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index b12d9cf..ee64ca2 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1555,7 +1555,7 @@
      *
      * <p>Note, that due to internal limitations, if there is already a web link
      * intent created for the specified document but with different options,
-     * then it may be overriden.
+     * then it may be overridden.
      *
      * <p>Providers are required to show confirmation UI for all new permissions granted
      * for the linked document.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 81b1921..0e782d7 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -771,7 +771,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #queryRoots(String[])
      * @see #queryRecentDocuments(String, String[])
@@ -828,7 +828,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #getDocumentType(String)
      */
@@ -903,7 +903,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      *
      * @see #createDocument(String, String, String)
      */
@@ -914,7 +914,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      *
      * @see #deleteDocument(String)
      */
@@ -925,7 +925,7 @@
 
     /**
      * Implementation is provided by the parent class. Throws by default, and
-     * cannot be overriden.
+     * cannot be overridden.
      */
     @Override
     public final int update(
@@ -1165,7 +1165,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1176,7 +1176,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1188,7 +1188,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1202,7 +1202,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocument(String, String, CancellationSignal)
      */
@@ -1216,7 +1216,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocumentThumbnail(String, Point, CancellationSignal)
      * @see #openTypedDocument(String, String, Bundle, CancellationSignal)
@@ -1229,7 +1229,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Cannot be overriden.
+     * Implementation is provided by the parent class. Cannot be overridden.
      *
      * @see #openDocumentThumbnail(String, Point, CancellationSignal)
      * @see #openTypedDocument(String, String, Bundle, CancellationSignal)
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 189b7b4..82459b1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -717,7 +717,11 @@
             /**
              * The picasa id of the image
              * <P>Type: TEXT</P>
+             *
+             * @deprecated this value was only relevant for images hosted on
+             *             Picasa, which are no longer supported.
              */
+            @Deprecated
             public static final String PICASA_ID = "picasa_id";
 
             /**
@@ -755,7 +759,12 @@
             /**
              * The mini thumb id.
              * <P>Type: INTEGER</P>
+             *
+             * @deprecated all thumbnails should be obtained via
+             *             {@link Images.Thumbnails#getThumbnail}, as this
+             *             value is no longer supported.
              */
+            @Deprecated
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
@@ -1947,7 +1956,12 @@
             /**
              * The mini thumb id.
              * <P>Type: INTEGER</P>
+             *
+             * @deprecated all thumbnails should be obtained via
+             *             {@link Images.Thumbnails#getThumbnail}, as this
+             *             value is no longer supported.
              */
+            @Deprecated
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 138e77b..02a5e6f 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -181,7 +181,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final Uri insert(Uri uri, ContentValues values) {
@@ -189,7 +189,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final int delete(Uri uri, String selection, String[] selectionArgs) {
@@ -197,7 +197,7 @@
     }
 
     /**
-     * Implementation is provided by the parent class. Throws by default, and cannot be overriden.
+     * Implementation is provided by the parent class. Throws by default, and cannot be overridden.
      */
     @Override
     public final int update(
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e007398..4c7f0f3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -363,6 +363,21 @@
             "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
 
     /**
+     * Activity Action: Show the "Open by Default" page in a particular application's details page.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * Input: The Intent's data URI specifies the application package name
+     * to be shown, with the "package" scheme. That is "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS =
+            "com.android.settings.APP_OPEN_BY_DEFAULT_SETTINGS";
+
+    /**
      * Activity Action: Show trusted credentials settings, opening to the user tab,
      * to allow management of installed credentials.
      * <p>
@@ -809,21 +824,6 @@
             "android.settings.APPLICATION_DETAILS_SETTINGS";
 
     /**
-     * Activity Action: Show the "Open by Default" page in a particular application's details page.
-     * <p>
-     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
-     * <p>
-     * Input: The Intent's data URI specifies the application package name
-     * to be shown, with the "package" scheme. That is "package:com.my.app".
-     * <p>
-     * Output: Nothing.
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE =
-            "android.settings.APPLICATION_DETAILS_SETTINGS_OPEN_BY_DEFAULT_PAGE";
-
-    /**
      * Activity Action: Show list of applications that have been running
      * foreground services (to the user "running in the background").
      * <p>
@@ -6508,6 +6508,25 @@
         public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
 
         /**
+         * Whether the user specifies a minimum ui timeout to override minimum ui timeout of
+         * accessibility service
+         *
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
+                "accessibility_minimum_ui_timeout_enabled";
+
+        /**
+         * Setting that specifies ui minimum timeout in milliseconds.
+         *
+         * @see #ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
+                "accessibility_minimum_ui_timeout_ms";
+
+        /**
          * List of the enabled print services.
          *
          * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade
@@ -8195,6 +8214,8 @@
             ZEN_SETTINGS_SUGGESTION_VIEWED,
             CHARGING_SOUNDS_ENABLED,
             CHARGING_VIBRATION_ENABLED,
+            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
+            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
         };
 
         /**
@@ -8349,6 +8370,8 @@
             VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
index b1ae7a5..fdbb1c2 100644
--- a/core/java/android/service/autofill/CustomDescription.java
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -314,7 +314,8 @@
          * is called multiple times passing the same {@code id}, only the last call will be used.
          *
          * @param id resource id of the child view.
-         * @param action action to be performed.
+         * @param action action to be performed. Must be an an implementation provided by the
+         * Android System.
          *
          * @return this builder
          *
diff --git a/core/java/android/service/autofill/OnClickAction.java b/core/java/android/service/autofill/OnClickAction.java
index 7439b00..8597a88 100644
--- a/core/java/android/service/autofill/OnClickAction.java
+++ b/core/java/android/service/autofill/OnClickAction.java
@@ -21,6 +21,9 @@
  *
  * <p>Typically used to switch the visibility of other views in a
  * {@link CustomDescription custom save UI}.
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface OnClickAction {
 }
diff --git a/core/java/android/service/autofill/Sanitizer.java b/core/java/android/service/autofill/Sanitizer.java
index 38757ac..8a1310d 100644
--- a/core/java/android/service/autofill/Sanitizer.java
+++ b/core/java/android/service/autofill/Sanitizer.java
@@ -21,6 +21,9 @@
  * <p>Typically used to avoid displaying the save UI for values that are autofilled but reformatted
  * by the app&mdash;for example, if the autofill service sends a credit card number
  * value as "004815162342108" and the app automatically changes it to "0048 1516 2342 108".
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface Sanitizer {
 }
diff --git a/core/java/android/service/autofill/Transformation.java b/core/java/android/service/autofill/Transformation.java
index aa8bc9b..de43955 100644
--- a/core/java/android/service/autofill/Transformation.java
+++ b/core/java/android/service/autofill/Transformation.java
@@ -20,6 +20,9 @@
  * template} at runtime, using the values of fields contained in the screen.
  *
  * <p>Typically used by {@link CustomDescription} to provide a customized autofill save UI.
+ *
+ * <p><b>Note:</b> This interface is not meant to be implemented by app developers; only
+ * implementations provided by the Android System can be used in other Autofill APIs.
  */
 public interface Transformation {
 }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 15b2aae..38de794 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -626,7 +627,7 @@
      * @see #startDozing
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean canDoze() {
         return mCanDoze;
     }
@@ -694,7 +695,7 @@
      * @see #startDozing
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void stopDozing() {
         if (mDozing) {
             mDozing = false;
@@ -716,7 +717,7 @@
      * @see #setDozing(boolean)
      * @hide For use by system UI components only.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isDozing() {
         return mDozing;
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d9ed2aa..d7fe15d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -280,7 +280,7 @@
 
     private final Object mLock = new Object();
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Handler mHandler;
 
     /** @hide */
@@ -989,6 +989,21 @@
     }
 
     /**
+     * Clears listener hints set via {@link #getCurrentListenerHints()}.
+     *
+     * <p>The service should wait for the {@link #onListenerConnected()} event
+     * before performing this operation.
+     */
+    public final void clearRequestedListenerHints() {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().clearRequestedListenerHints(mWrapper);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
      * Sets the desired {@link #getCurrentListenerHints() listener hints}.
      *
      * <p>
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index f90eb14..e819c96 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,7 @@
 
 package android.service.notification;
 
+import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
@@ -763,6 +764,145 @@
         }
     };
 
+    /**
+     * @return notification policy based on manual and automatic rules
+     */
+    public Policy getConsolidatedNotificationPolicy() {
+        ZenPolicy policy = new ZenPolicy();
+
+        // assumption: manual rule always uses the default policy
+        for (ZenRule rule : automaticRules.values()) {
+            if (rule.isAutomaticActive()) {
+                if (rule.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+                    policy.apply(rule.zenPolicy);
+                }
+            }
+        }
+
+        return toNotificationPolicy(policy);
+    }
+
+    /**
+     * Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its
+     * defaults for all unset values in zenPolicy
+     */
+    public Policy toNotificationPolicy(ZenPolicy zenPolicy) {
+        NotificationManager.Policy defaultPolicy = toNotificationPolicy();
+        int priorityCategories = 0;
+        int suppressedVisualEffects = 0;
+        int callSenders = defaultPolicy.priorityCallSenders;
+        int messageSenders = defaultPolicy.priorityMessageSenders;
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REMINDERS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REMINDERS, defaultPolicy))) {
+            priorityCategories |= PRIORITY_CATEGORY_REMINDERS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_EVENTS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_EVENTS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
+            messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityMessageSenders());
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
+            messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityCallSenders());
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS,
+                        defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_ALARMS,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_ALARMS, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MEDIA,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MEDIA, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_MEDIA;
+        }
+
+        if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_SYSTEM,
+                isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_SYSTEM, defaultPolicy))) {
+            priorityCategories |= Policy.PRIORITY_CATEGORY_SYSTEM;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_LIGHTS,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_LIGHTS,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_PEEK,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_PEEK,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_STATUS_BAR,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_STATUS_BAR,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_BADGE,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_BADGE,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_AMBIENT,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_AMBIENT,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+        }
+
+        if (!zenPolicy.isVisualEffectAllowed(ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST,
+                isVisualEffectAllowed(Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST,
+                        defaultPolicy))) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+        }
+
+        return new NotificationManager.Policy(priorityCategories, callSenders,
+                messageSenders, suppressedVisualEffects);
+    }
+
+    private boolean isPriorityCategoryEnabled(int categoryType, Policy policy) {
+        return (policy.priorityCategories & categoryType) != 0;
+    }
+
+    private boolean isVisualEffectAllowed(int visualEffect, Policy policy) {
+        return (policy.suppressedVisualEffects & visualEffect) == 0;
+    }
+
+    private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders) {
+        switch (senders) {
+            case ZenPolicy.PEOPLE_TYPE_ANYONE:
+                return Policy.PRIORITY_SENDERS_ANY;
+            case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+                return Policy.PRIORITY_SENDERS_CONTACTS;
+            case ZenPolicy.PEOPLE_TYPE_STARRED:
+            default:
+                return Policy.PRIORITY_SENDERS_STARRED;
+        }
+
+    }
+
     public Policy toNotificationPolicy() {
         int priorityCategories = 0;
         int priorityCallSenders = Policy.PRIORITY_SENDERS_CONTACTS;
@@ -1315,6 +1455,7 @@
         @UnsupportedAppUsage
         public long creationTime;        // required for automatic
         public String enabler;          // package name, only used for manual rules.
+        public ZenPolicy zenPolicy;
 
         public ZenRule() { }
 
@@ -1335,6 +1476,7 @@
             if (source.readInt() == 1) {
                 enabler = source.readString();
             }
+            zenPolicy = source.readParcelable(null);
         }
 
         @Override
@@ -1369,6 +1511,7 @@
             } else {
                 dest.writeInt(0);
             }
+            dest.writeParcelable(zenPolicy, 0);
         }
 
         @Override
@@ -1384,6 +1527,7 @@
                     .append(",component=").append(component)
                     .append(",creationTime=").append(creationTime)
                     .append(",enabler=").append(enabler)
+                    .append(",zenPolicy=").append(zenPolicy)
                     .append(']').toString();
         }
 
@@ -1407,7 +1551,9 @@
             if (component != null) {
                 component.writeToProto(proto, ZenRuleProto.COMPONENT);
             }
-
+            if (zenPolicy != null) {
+                zenPolicy.writeToProto(proto, ZenRuleProto.ZEN_POLICY);
+            }
             proto.end(token);
         }
 
@@ -1454,9 +1600,12 @@
             if (creationTime != to.creationTime) {
                 d.addLine(item, "creationTime", creationTime, to.creationTime);
             }
-            if (enabler != to.enabler) {
+            if (!Objects.equals(enabler, to.enabler)) {
                 d.addLine(item, "enabler", enabler, to.enabler);
             }
+            if (!Objects.equals(zenPolicy, to.zenPolicy)) {
+                d.addLine(item, "zenPolicy", zenPolicy, to.zenPolicy);
+            }
         }
 
         @Override
@@ -1472,13 +1621,14 @@
                     && Objects.equals(other.condition, condition)
                     && Objects.equals(other.component, component)
                     && Objects.equals(other.id, id)
-                    && Objects.equals(other.enabler, enabler);
+                    && Objects.equals(other.enabler, enabler)
+                    && Objects.equals(other.zenPolicy, zenPolicy);
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
-                    component, id, enabler);
+                    component, id, enabler, zenPolicy);
         }
 
         public boolean isAutomaticActive() {
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
new file mode 100644
index 0000000..1ccf529
--- /dev/null
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -0,0 +1,897 @@
+/*
+ * 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.service.notification;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * ZenPolicy determines whether to allow certain notifications and their corresponding sounds to
+ * play when a device is in Do Not Disturb mode.
+ * ZenPolicy also dictates the visual effects of notifications that are intercepted when
+ * a device is in Do Not Disturb mode.
+ */
+public final class ZenPolicy implements Parcelable {
+    private ArrayList<Integer> mPriorityCategories;
+    private ArrayList<Integer> mVisualEffects;
+    private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
+    private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
+
+    /** @hide */
+    @IntDef(prefix = { "PRIORITY_CATEGORY_" }, value = {
+            PRIORITY_CATEGORY_REMINDERS,
+            PRIORITY_CATEGORY_EVENTS,
+            PRIORITY_CATEGORY_MESSAGES,
+            PRIORITY_CATEGORY_CALLS,
+            PRIORITY_CATEGORY_REPEAT_CALLERS,
+            PRIORITY_CATEGORY_ALARMS,
+            PRIORITY_CATEGORY_MEDIA,
+            PRIORITY_CATEGORY_SYSTEM,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PriorityCategory {}
+
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_REMINDERS = 0;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_EVENTS = 1;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_MESSAGES = 2;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_CALLS = 3;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 4;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_ALARMS = 5;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_MEDIA = 6;
+    /** @hide */
+    public static final int PRIORITY_CATEGORY_SYSTEM = 7;
+
+    /** @hide */
+    @IntDef(prefix = { "VISUAL_EFFECT_" }, value = {
+            VISUAL_EFFECT_FULL_SCREEN_INTENT,
+            VISUAL_EFFECT_LIGHTS,
+            VISUAL_EFFECT_PEEK,
+            VISUAL_EFFECT_STATUS_BAR,
+            VISUAL_EFFECT_BADGE,
+            VISUAL_EFFECT_AMBIENT,
+            VISUAL_EFFECT_NOTIFICATION_LIST,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VisualEffect {}
+
+    /** @hide */
+    public static final int VISUAL_EFFECT_FULL_SCREEN_INTENT = 0;
+    /** @hide */
+    public static final int VISUAL_EFFECT_LIGHTS = 1;
+    /** @hide */
+    public static final int VISUAL_EFFECT_PEEK = 2;
+    /** @hide */
+    public static final int VISUAL_EFFECT_STATUS_BAR = 3;
+    /** @hide */
+    public static final int VISUAL_EFFECT_BADGE = 4;
+    /** @hide */
+    public static final int VISUAL_EFFECT_AMBIENT = 5;
+    /** @hide */
+    public static final int VISUAL_EFFECT_NOTIFICATION_LIST = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "PEOPLE_TYPE_" }, value = {
+            PEOPLE_TYPE_UNSET,
+            PEOPLE_TYPE_ANYONE,
+            PEOPLE_TYPE_CONTACTS,
+            PEOPLE_TYPE_STARRED,
+            PEOPLE_TYPE_NONE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PeopleType {}
+
+    /**
+     * Used to indicate no preference for the type of people that can bypass dnd for either
+     * calls or messages.
+     */
+    public static final int PEOPLE_TYPE_UNSET = 0;
+
+    /**
+     * Used to indicate all calls or messages can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_ANYONE = 1;
+
+    /**
+     * Used to indicate calls or messages from contacts can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_CONTACTS = 2;
+
+    /**
+     * Used to indicate calls or messages from starred contacts can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_STARRED = 3;
+
+    /**
+     * Used to indicate no calls or messages can bypass dnd.
+     */
+    public static final int PEOPLE_TYPE_NONE = 4;
+
+    /** @hide */
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_UNSET,
+            STATE_ALLOW,
+            STATE_DISALLOW,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
+     * Indicates no preference for whether a type of sound or visual effect is or isn't allowed
+     * to play/show when DND is active.  Will default to the current set policy.
+     */
+    public static final int STATE_UNSET = 0;
+
+    /**
+     * Indicates a type of sound or visual effect is allowed to play/show when DND is active.
+     */
+    public static final int STATE_ALLOW = 1;
+
+    /**
+     * Indicates a type of sound or visual effect is not allowed to play/show when DND is active.
+     */
+    public static final int STATE_DISALLOW = 2;
+
+    /** @hide */
+    public ZenPolicy() {
+        mPriorityCategories = new ArrayList<>(Collections.nCopies(8, 0));
+        mVisualEffects = new ArrayList<>(Collections.nCopies(7, 0));
+    }
+
+    /**
+     * Message senders that can bypass DND.
+     * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+     * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+     */
+    public @PeopleType int getPriorityMessageSenders() {
+        return mPriorityMessages;
+    }
+
+    /**
+     * Callers that can bypass DND.
+     * @return {@link #PEOPLE_TYPE_UNSET}, {@link #PEOPLE_TYPE_ANYONE},
+     * {@link #PEOPLE_TYPE_CONTACTS}, {@link #PEOPLE_TYPE_STARRED} or {@link #PEOPLE_TYPE_NONE}
+     */
+    public @PeopleType int getPriorityCallSenders() {
+        return mPriorityCalls;
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_REMINDER} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryReminders() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_REMINDERS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_EVENT} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryEvents() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_EVENTS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_MESSAGE} to play sounds and visually appear
+     * or to intercept them when DND is active.  Types of message senders that are allowed
+     * are specified by {@link #getPriorityMessageSenders}.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryMessages() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_MESSAGES);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_CALL} to play sounds and visually appear
+     * or to intercept them when DND is active.  Types of callers that are allowed
+     * are specified by {@link #getPriorityCallSenders()}.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryCalls() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_CALLS);
+    }
+
+    /**
+     * Whether this policy wants to allow repeat callers (notifications with category
+     * {@link Notification#CATEGORY_CALL} that have recently called) to play sounds and
+     * visually appear or to intercept them when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryRepeatCallers() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_REPEAT_CALLERS);
+    }
+
+    /**
+     * Whether this policy wants to allow notifications with category
+     * {@link Notification#CATEGORY_ALARM} to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * When alarms are {@link #STATE_DISALLOW disallowed}, the alarm stream will be muted when DND
+     * is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryAlarms() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_ALARMS);
+    }
+
+    /**
+     * Whether this policy wants to allow media notifications to play sounds and visually appear
+     * or to intercept them when DND is active.
+     * When media is {@link #STATE_DISALLOW disallowed}, the media stream will be muted when DND is
+     * active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategoryMedia() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_MEDIA);
+    }
+
+    /**
+     * Whether this policy wants to allow system sounds when DND is active.
+     * When system is {@link #STATE_DISALLOW}, the system stream will be muted when DND is active.
+     * @return {@link #STATE_UNSET}, {@link #STATE_ALLOW} or {@link #STATE_DISALLOW}
+     */
+    public @State int getPriorityCategorySystem() {
+        return mPriorityCategories.get(PRIORITY_CATEGORY_SYSTEM);
+    }
+
+    /**
+     * Whether this policy allows {@link Notification#fullScreenIntent full screen intents} from
+     * notifications intercepted by DND.
+     */
+    public @State int getVisualEffectFullScreenIntent() {
+        return mVisualEffects.get(VISUAL_EFFECT_FULL_SCREEN_INTENT);
+    }
+
+    /**
+     * Whether this policy allows {@link NotificationChannel#shouldShowLights() notification
+     * lights} from notifications intercepted by DND.
+     */
+    public @State int getVisualEffectLights() {
+        return mVisualEffects.get(VISUAL_EFFECT_LIGHTS);
+    }
+
+    /**
+     * Whether this policy allows peeking from notifications intercepted by DND.
+     */
+    public @State int getVisualEffectPeek() {
+        return mVisualEffects.get(VISUAL_EFFECT_PEEK);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing in the status bar
+     * on devices that support status bars.
+     */
+    public @State int getVisualEffectStatusBar() {
+        return mVisualEffects.get(VISUAL_EFFECT_STATUS_BAR);
+    }
+
+    /**
+     * Whether this policy allows {@link NotificationChannel#canShowBadge() badges} from
+     * notifications intercepted by DND on devices that support badging.
+     */
+    public @State int getVisualEffectBadge() {
+        return mVisualEffects.get(VISUAL_EFFECT_BADGE);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing on ambient
+     * displays on devices that support ambient display.
+     */
+    public @State int getVisualEffectAmbient() {
+        return mVisualEffects.get(VISUAL_EFFECT_AMBIENT);
+    }
+
+    /**
+     * Whether this policy allows notifications intercepted by DND from appearing in notification
+     * list views like the notification shade or lockscreen on devices that support those
+     * views.
+     */
+    public @State int getVisualEffectNotificationList() {
+        return mVisualEffects.get(VISUAL_EFFECT_NOTIFICATION_LIST);
+    }
+
+    /**
+     * Builder class for {@link ZenPolicy} objects.
+     * Provides a convenient way to set the various fields of a {@link ZenPolicy}.  If a field
+     * is not set, it is (@link STATE_UNSET} and will not change the current set policy.
+     */
+    public static class Builder {
+        private ZenPolicy mZenPolicy;
+
+        public Builder() {
+            mZenPolicy = new ZenPolicy();
+        }
+
+        /**
+         * Builds the current ZenPolicy.
+         */
+        public ZenPolicy build() {
+            return mZenPolicy.copy();
+        }
+
+        /**
+         * Allows all notifications to bypass DND and unmutes all streams.
+         */
+        public Builder allowAllSounds() {
+            for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+                mZenPolicy.mPriorityCategories.set(i, STATE_ALLOW);
+            }
+            mZenPolicy.mPriorityMessages = PEOPLE_TYPE_ANYONE;
+            mZenPolicy.mPriorityCalls = PEOPLE_TYPE_ANYONE;
+            return this;
+        }
+
+        /**
+         * Intercepts all notifications and prevents them from playing sounds
+         * when DND is active. Also mutes alarm, system and media streams.
+         * Notification channels can still play sounds only if they
+         * {@link NotificationChannel#canBypassDnd can bypass DND}. If no channels can bypass DND,
+         * the ringer stream is also muted.
+         */
+        public Builder disallowAllSounds() {
+            for (int i = 0; i < mZenPolicy.mPriorityCategories.size(); i++) {
+                mZenPolicy.mPriorityCategories.set(i, STATE_DISALLOW);
+            }
+            mZenPolicy.mPriorityMessages = PEOPLE_TYPE_NONE;
+            mZenPolicy.mPriorityCalls = PEOPLE_TYPE_NONE;
+            return this;
+        }
+
+        /**
+         * Allows notifications intercepted by DND to show on all surfaces when DND is active.
+         */
+        public Builder showAllVisualEffects() {
+            for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+                mZenPolicy.mVisualEffects.set(i, STATE_ALLOW);
+            }
+            return this;
+        }
+
+        /**
+         * Disallows notifications intercepted by DND from showing when DND is active.
+         */
+        public Builder hideAllVisualEffects() {
+            for (int i = 0; i < mZenPolicy.mVisualEffects.size(); i++) {
+                mZenPolicy.mVisualEffects.set(i, STATE_DISALLOW);
+            }
+            return this;
+        }
+
+        /**
+         * Unsets a priority category, neither allowing or disallowing. When applying this policy,
+         * unset categories will default to the current applied policy.
+         * @hide
+         */
+        public Builder unsetPriorityCategory(@PriorityCategory int category) {
+            mZenPolicy.mPriorityCategories.set(category, STATE_UNSET);
+
+            if (category == PRIORITY_CATEGORY_MESSAGES) {
+                mZenPolicy.mPriorityMessages = STATE_UNSET;
+            } else if (category == PRIORITY_CATEGORY_CALLS) {
+                mZenPolicy.mPriorityCalls = STATE_UNSET;
+            }
+
+            return this;
+        }
+
+        /**
+         * Unsets a visual effect, neither allowing or disallowing. When applying this policy,
+         * unset effects will default to the current applied policy.
+         * @hide
+         */
+        public Builder unsetVisualEffect(@VisualEffect int effect) {
+            mZenPolicy.mVisualEffects.set(effect, STATE_UNSET);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_REMINDER}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         */
+        public Builder allowReminders(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REMINDERS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_EVENT}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         */
+        public Builder allowEvents(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_EVENTS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_MESSAGE}
+         * that match audienceType to play sounds and visually appear or to intercept
+         * them when DND is active.
+         * @param audienceType message senders that are allowed to bypass DND
+         */
+        public Builder allowMessages(@PeopleType int audienceType) {
+            if (audienceType == STATE_UNSET) {
+                return unsetPriorityCategory(PRIORITY_CATEGORY_MESSAGES);
+            }
+
+            if (audienceType == PEOPLE_TYPE_NONE) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_DISALLOW);
+            } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+                    || audienceType == PEOPLE_TYPE_STARRED) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MESSAGES, STATE_ALLOW);
+            } else {
+                return this;
+            }
+
+            mZenPolicy.mPriorityMessages = audienceType;
+            return this;
+        }
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_CALL}
+         * that match audienceType to play sounds and visually appear or to intercept
+         * them when DND is active.
+         * @param audienceType callers that are allowed to bypass DND
+         */
+        public Builder allowCalls(@PeopleType int audienceType) {
+            if (audienceType == STATE_UNSET) {
+                return unsetPriorityCategory(PRIORITY_CATEGORY_CALLS);
+            }
+
+            if (audienceType == PEOPLE_TYPE_NONE) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_DISALLOW);
+            } else if (audienceType == PEOPLE_TYPE_ANYONE || audienceType == PEOPLE_TYPE_CONTACTS
+                    || audienceType == PEOPLE_TYPE_STARRED) {
+                mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_CALLS, STATE_ALLOW);
+            } else {
+                return this;
+            }
+
+            mZenPolicy.mPriorityCalls = audienceType;
+            return this;
+        }
+
+        /**
+         * Whether to allow repeat callers (notifications with category
+         * {@link Notification#CATEGORY_CALL} that have recently called
+         * to play sounds and visually appear.
+         */
+        public Builder allowRepeatCallers(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_REPEAT_CALLERS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+
+        /**
+         * Whether to allow notifications with category {@link Notification#CATEGORY_ALARM}
+         * to play sounds and visually appear or to intercept them when DND is active.
+         * Disallowing alarms will mute the alarm stream when DND is active.
+         */
+        public Builder allowAlarms(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_ALARMS,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow media notifications to play sounds and visually
+         * appear or to intercept them when DND is active.
+         * Disallowing media will mute the media stream when DND is active.
+         */
+        public Builder allowMedia(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_MEDIA,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether to allow system sounds to play when DND is active.
+         * Disallowing system sounds will mute the system stream when DND is active.
+         */
+        public Builder allowSystem(boolean allow) {
+            mZenPolicy.mPriorityCategories.set(PRIORITY_CATEGORY_SYSTEM,
+                    allow ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link Notification#fullScreenIntent full screen intents} that are intercepted
+         * by DND are shown.
+         */
+        public Builder showFullScreenIntent(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_FULL_SCREEN_INTENT,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link NotificationChannel#shouldShowLights() notification lights} from
+         * notifications intercepted by DND are blocked.
+         */
+        public Builder showLights(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_LIGHTS,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notifications intercepted by DND are prevented from peeking.
+         */
+        public Builder showPeeking(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_PEEK,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notifications intercepted by DND are prevented from appearing in the status bar
+         * on devices that support status bars.
+         */
+        public Builder showStatusBarIcons(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_STATUS_BAR,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether {@link NotificationChannel#canShowBadge() badges} from
+         * notifications intercepted by DND are allowed on devices that support badging.
+         */
+        public Builder showBadges(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_BADGE,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing on ambient displays
+         * on devices that support ambient display.
+         */
+        public Builder showInAmbientDisplay(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_AMBIENT,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+
+        /**
+         * Whether notification intercepted by DND are prevented from appearing in notification
+         * list views like the notification shade or lockscreen on devices that support those
+         * views.
+         */
+        public Builder showInNotificationList(boolean show) {
+            mZenPolicy.mVisualEffects.set(VISUAL_EFFECT_NOTIFICATION_LIST,
+                    show ? STATE_ALLOW : STATE_DISALLOW);
+            return this;
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeList(mPriorityCategories);
+        dest.writeList(mVisualEffects);
+        dest.writeInt(mPriorityCalls);
+        dest.writeInt(mPriorityMessages);
+    }
+
+    public static final Parcelable.Creator<ZenPolicy> CREATOR =
+            new Parcelable.Creator<ZenPolicy>() {
+        @Override
+        public ZenPolicy createFromParcel(Parcel source) {
+            ZenPolicy policy = new ZenPolicy();
+            policy.mPriorityCategories = source.readArrayList(Integer.class.getClassLoader());
+            policy.mVisualEffects = source.readArrayList(Integer.class.getClassLoader());
+            policy.mPriorityCalls = source.readInt();
+            policy.mPriorityMessages = source.readInt();
+            return policy;
+        }
+
+        @Override
+        public ZenPolicy[] newArray(int size) {
+            return new ZenPolicy[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return new StringBuilder(ZenPolicy.class.getSimpleName())
+                .append('{')
+                .append("priorityCategories=[").append(priorityCategoriesToString())
+                .append("], visualEffects=[").append(visualEffectsToString())
+                .append(", priorityCalls=").append(stateToString(mPriorityCalls))
+                .append("], priorityMessages=").append(stateToString(mPriorityMessages))
+                .append('}')
+                .toString();
+    }
+
+
+    private String priorityCategoriesToString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < mPriorityCategories.size(); i++) {
+            if (mPriorityCategories.get(i) != STATE_UNSET) {
+                builder.append(indexToCategory(i))
+                        .append("=")
+                        .append(stateToString(mPriorityCategories.get(i)))
+                        .append(" ");
+            }
+
+        }
+        return builder.toString();
+    }
+
+    private String visualEffectsToString() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < mVisualEffects.size(); i++) {
+            if (mVisualEffects.get(i) != STATE_UNSET) {
+                builder.append(indexToVisualEffect(i))
+                        .append("=")
+                        .append(stateToString(mVisualEffects.get(i)))
+                        .append(" ");
+            }
+
+        }
+        return builder.toString();
+    }
+
+    private String indexToVisualEffect(@VisualEffect int visualEffectIndex) {
+        switch (visualEffectIndex) {
+            case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+                return "fullScreenIntent";
+            case VISUAL_EFFECT_LIGHTS:
+                return "lights";
+            case VISUAL_EFFECT_PEEK:
+                return "peek";
+            case VISUAL_EFFECT_STATUS_BAR:
+                return "statusBar";
+            case VISUAL_EFFECT_BADGE:
+                return "badge";
+            case VISUAL_EFFECT_AMBIENT:
+                return "ambient";
+            case VISUAL_EFFECT_NOTIFICATION_LIST:
+                return "notificationList";
+        }
+        return null;
+    }
+
+    private String indexToCategory(@PriorityCategory int categoryIndex) {
+        switch (categoryIndex) {
+            case PRIORITY_CATEGORY_REMINDERS:
+                return "reminders";
+            case PRIORITY_CATEGORY_EVENTS:
+                return "events";
+            case PRIORITY_CATEGORY_MESSAGES:
+                return "messages";
+            case PRIORITY_CATEGORY_CALLS:
+                return "calls";
+            case PRIORITY_CATEGORY_REPEAT_CALLERS:
+                return "repeatCallers";
+            case PRIORITY_CATEGORY_ALARMS:
+                return "alarms";
+            case PRIORITY_CATEGORY_MEDIA:
+                return "media";
+            case PRIORITY_CATEGORY_SYSTEM:
+                return "system";
+        }
+        return null;
+    }
+
+    private String stateToString(@State int state) {
+        switch (state) {
+            case STATE_UNSET:
+                return "unset";
+            case STATE_DISALLOW:
+                return "disallow";
+            case STATE_ALLOW:
+                return "allow";
+        }
+        return null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof ZenPolicy)) return false;
+        if (o == this) return true;
+        final ZenPolicy other = (ZenPolicy) o;
+
+        return Objects.equals(other.mPriorityCategories, mPriorityCategories)
+                && Objects.equals(other.mVisualEffects, mVisualEffects)
+                && other.mPriorityCalls == mPriorityCalls
+                && other.mPriorityMessages == mPriorityMessages;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPriorityCategories, mVisualEffects, mPriorityCalls, mPriorityMessages);
+    }
+
+    private @ZenPolicy.State int getZenPolicyPriorityCategoryState(@PriorityCategory int
+            category) {
+        switch (category) {
+            case PRIORITY_CATEGORY_REMINDERS:
+                return getPriorityCategoryReminders();
+            case PRIORITY_CATEGORY_EVENTS:
+                return getPriorityCategoryEvents();
+            case PRIORITY_CATEGORY_MESSAGES:
+                return getPriorityCategoryMessages();
+            case PRIORITY_CATEGORY_CALLS:
+                return getPriorityCategoryCalls();
+            case PRIORITY_CATEGORY_REPEAT_CALLERS:
+                return getPriorityCategoryRepeatCallers();
+            case PRIORITY_CATEGORY_ALARMS:
+                return getPriorityCategoryAlarms();
+            case PRIORITY_CATEGORY_MEDIA:
+                return getPriorityCategoryMedia();
+            case PRIORITY_CATEGORY_SYSTEM:
+                return getPriorityCategorySystem();
+        }
+        return -1;
+    }
+
+    private @ZenPolicy.State int getZenPolicyVisualEffectState(@VisualEffect int effect) {
+        switch (effect) {
+            case VISUAL_EFFECT_FULL_SCREEN_INTENT:
+                return getVisualEffectFullScreenIntent();
+            case VISUAL_EFFECT_LIGHTS:
+                return getVisualEffectLights();
+            case VISUAL_EFFECT_PEEK:
+                return getVisualEffectPeek();
+            case VISUAL_EFFECT_STATUS_BAR:
+                return getVisualEffectStatusBar();
+            case VISUAL_EFFECT_BADGE:
+                return getVisualEffectBadge();
+            case VISUAL_EFFECT_AMBIENT:
+                return getVisualEffectAmbient();
+            case VISUAL_EFFECT_NOTIFICATION_LIST:
+                return getVisualEffectNotificationList();
+        }
+        return -1;
+    }
+
+    /** @hide */
+    public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
+        switch (getZenPolicyPriorityCategoryState(category)) {
+            case ZenPolicy.STATE_ALLOW:
+                return true;
+            case ZenPolicy.STATE_DISALLOW:
+                return false;
+            default:
+                return defaultVal;
+        }
+    }
+
+    /** @hide */
+    public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) {
+        switch (getZenPolicyVisualEffectState(effect)) {
+            case ZenPolicy.STATE_ALLOW:
+                return true;
+            case ZenPolicy.STATE_DISALLOW:
+                return false;
+            default:
+                return defaultVal;
+        }
+    }
+
+    /**
+     * Applies another policy on top of this policy
+     * @hide
+     */
+    public void apply(ZenPolicy policyToApply) {
+        // apply priority categories
+        for (int category = 0; category < mPriorityCategories.size(); category++) {
+            if (mPriorityCategories.get(category) == STATE_DISALLOW) {
+                // if a priority category is already disallowed by the policy, cannot allow
+                continue;
+            }
+
+            @State int newState = policyToApply.mPriorityCategories.get(category);
+            if (newState != STATE_UNSET) {
+                mPriorityCategories.set(category, newState);
+
+                if (category == PRIORITY_CATEGORY_MESSAGES
+                        && mPriorityMessages < policyToApply.mPriorityMessages) {
+                    mPriorityMessages = policyToApply.mPriorityMessages;
+                } else if (category == PRIORITY_CATEGORY_CALLS
+                        && mPriorityCalls < policyToApply.mPriorityCalls) {
+                    mPriorityCalls = policyToApply.mPriorityCalls;
+                }
+            }
+        }
+
+        // apply visual effects
+        for (int visualEffect = 0; visualEffect < mVisualEffects.size(); visualEffect++) {
+            if (mVisualEffects.get(visualEffect) == STATE_DISALLOW) {
+                // if a visual effect is already disallowed by the policy, cannot allow
+                continue;
+            }
+
+            if (policyToApply.mVisualEffects.get(visualEffect) != STATE_UNSET) {
+                mVisualEffects.set(visualEffect, policyToApply.mVisualEffects.get(visualEffect));
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+
+        proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders());
+        proto.write(ZenPolicyProto.EVENTS, getPriorityCategoryEvents());
+        proto.write(ZenPolicyProto.MESSAGES, getPriorityCategoryMessages());
+        proto.write(ZenPolicyProto.CALLS, getPriorityCategoryCalls());
+        proto.write(ZenPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
+        proto.write(ZenPolicyProto.ALARMS, getPriorityCategoryAlarms());
+        proto.write(ZenPolicyProto.MEDIA, getPriorityCategoryMedia());
+        proto.write(ZenPolicyProto.SYSTEM, getPriorityCategorySystem());
+
+        proto.write(ZenPolicyProto.FULL_SCREEN_INTENT, getVisualEffectFullScreenIntent());
+        proto.write(ZenPolicyProto.LIGHTS, getVisualEffectLights());
+        proto.write(ZenPolicyProto.PEEK, getVisualEffectPeek());
+        proto.write(ZenPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
+        proto.write(ZenPolicyProto.BADGE, getVisualEffectBadge());
+        proto.write(ZenPolicyProto.AMBIENT, getVisualEffectAmbient());
+        proto.write(ZenPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
+
+        proto.write(ZenPolicyProto.PRIORITY_MESSAGES, getPriorityMessageSenders());
+        proto.write(ZenPolicyProto.PRIORITY_CALLS, getPriorityCallSenders());
+        proto.end(token);
+    }
+
+    /**
+     * Makes deep copy of this ZenPolicy.
+     * @hide
+     */
+    public ZenPolicy copy() {
+        final Parcel parcel = Parcel.obtain();
+        try {
+            writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index c46c831..c928da1 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -23,6 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.os.Build;
 import android.text.style.ReplacementSpan;
 import android.text.style.UpdateLayout;
 import android.text.style.WrapTogetherSpan;
@@ -354,7 +355,7 @@
      * @deprecated Use {@link Builder} instead.
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public DynamicLayout(@NonNull CharSequence base, @NonNull CharSequence display,
                          @NonNull TextPaint paint,
                          @IntRange(from = 0) int width,
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 5adb1ca..e1ffef0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Paint;
+import android.os.Build;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
 import android.text.style.LineHeightSpan;
@@ -1293,7 +1294,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getHeight(boolean cap) {
         if (cap && mLineCount > mMaximumVisibleLineCount && mMaxLineHeight == -1
                 && Log.isLoggable(TAG, Log.WARN)) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index bf2d600..ad7a851 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
+import android.os.Build;
 import android.text.Layout.Directions;
 import android.text.Layout.TabStops;
 import android.text.style.CharacterStyle;
@@ -61,7 +62,7 @@
     private TabStops mTabs;
     private char[] mChars;
     private boolean mCharsValid;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Spanned mSpanned;
     private PrecomputedText mComputed;
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b5ade2a..ff6e86e 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -39,13 +39,13 @@
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
         DEFAULT_FLAGS = new HashMap<>();
-        DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
         DEFAULT_FLAGS.put("settings_mobile_network_v2", "false");
         DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
+        DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
     }
 
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
new file mode 100644
index 0000000..209451b
--- /dev/null
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -0,0 +1,978 @@
+/*
+ * 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.util.proto;
+
+import android.annotation.TestApi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+
+/**
+ * Class to read to a protobuf stream.
+ *
+ * Each read method takes an ID code from the protoc generated classes
+ * and return a value of the field. To read a nested object, call #start
+ * and then #end when you are done.
+ *
+ * The ID codes have type information embedded into them, so if you call
+ * the incorrect function you will get an IllegalArgumentException.
+ *
+ * nextField will return the field number of the next field, which can be
+ * matched to the protoc generated ID code and used to determine how to
+ * read the next field.
+ *
+ * It is STRONGLY RECOMMENDED to read from the ProtoInputStream with a switch
+ * statement wrapped in a while loop. Additionally, it is worth logging or
+ * storing unexpected fields or ones that do not match the expected wire type
+ *
+ * ex:
+ * void parseFromProto(ProtoInputStream stream) {
+ *     while(stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ *         try {
+ *             switch (stream.getFieldNumber()) {
+ *                 case (int) DummyProto.NAME:
+ *                     mName = stream.readString(DummyProto.NAME);
+ *                     break;
+ *                 case (int) DummyProto.VALUE:
+ *                     mValue = stream.readInt(DummyProto.VALUE);
+ *                     break;
+ *                 default:
+ *                     LOG(TAG, "Unhandled field in proto!\n"
+ *                              + ProtoUtils.currentFieldToString(stream));
+ *             }
+ *         } catch (WireTypeMismatchException wtme) {
+ *             LOG(TAG, "Wire Type mismatch in proto!\n" + ProtoUtils.currentFieldToString(stream));
+ *         }
+ *     }
+ * }
+ *
+ * @hide
+ */
+@TestApi
+public final class ProtoInputStream extends ProtoStream {
+
+    public static final int NO_MORE_FIELDS = -1;
+
+    /**
+     * Our stream.  If there is one.
+     */
+    private InputStream mStream;
+
+    /**
+     * The field number of the current field. Will be equal to NO_MORE_FIELDS if end of message is
+     * reached
+     */
+    private int mFieldNumber;
+
+    /**
+     * The wire type of the current field
+     */
+    private int mWireType;
+
+    private static final byte STATE_STARTED_FIELD_READ = 1 << 0;
+    private static final byte STATE_READING_PACKED = 1 << 1;
+    private static final byte STATE_FIELD_MISS = 2 << 1;
+
+    /**
+     * Tracks some boolean states for the proto input stream
+     * bit 0: Started Field Read, true - tag has been read, ready to read field data.
+     * false - field data has been read, reading to start next field.
+     * bit 1: Reading Packed Field, true - currently reading values from a packed field
+     * false - not reading from packed field.
+     */
+    private byte mState = 0;
+
+    /**
+     * Keeps track of the currently read nested Objects, for end object sanity checking and debug
+     */
+    private ArrayList<Long> mExpectedObjectTokenStack = null;
+
+    /**
+     * Current nesting depth of start calls.
+     */
+    private int mDepth = -1;
+
+    /**
+     * Buffer for the to be read data. If mStream is not null, it will be constantly refilled from
+     * the stream.
+     */
+    private byte[] mBuffer;
+
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    /**
+     * Size of the buffer if reading from a stream.
+     */
+    private final int mBufferSize;
+
+    /**
+     * The number of bytes that have been skipped or dropped from the buffer.
+     */
+    private int mDiscardedBytes = 0;
+
+    /**
+     * Current offset in the buffer
+     * mOffset + mDiscardedBytes = current offset in proto binary
+     */
+    private int mOffset = 0;
+
+    /**
+     * Note the offset of the last byte in the buffer. Usually will equal the size of the buffer.
+     * mEnd + mDiscardedBytes = the last known byte offset + 1
+     */
+    private int mEnd = 0;
+
+    /**
+     * Packed repeated fields are not read in one go. mPackedEnd keeps track of where the packed
+     * field ends in the proto binary if current field is packed.
+     */
+    private int mPackedEnd = 0;
+
+    /**
+     * Construct a ProtoInputStream on top of an InputStream to read a proto. Also specify the
+     * number of bytes the ProtoInputStream will buffer from the input stream
+     *
+     * @param stream from which the proto is read
+     */
+    public ProtoInputStream(InputStream stream, int bufferSize) {
+        mStream = stream;
+        if (bufferSize > 0) {
+            mBufferSize = bufferSize;
+        } else {
+            mBufferSize = DEFAULT_BUFFER_SIZE;
+        }
+        mBuffer = new byte[mBufferSize];
+    }
+
+    /**
+     * Construct a ProtoInputStream on top of an InputStream to read a proto
+     *
+     * @param stream from which the proto is read
+     */
+    public ProtoInputStream(InputStream stream) {
+        this(stream, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a ProtoInputStream to read a proto directly from a byte array
+     *
+     * @param buffer - the byte array to be parsed
+     */
+    public ProtoInputStream(byte[] buffer) {
+        mBufferSize = buffer.length;
+        mEnd = buffer.length;
+        mBuffer = buffer;
+        mStream = null;
+    }
+
+    /**
+     * Get the field number of the current field.
+     */
+    public int getFieldNumber() {
+        return mFieldNumber;
+    }
+
+    /**
+     * Get the wire type of the current field.
+     *
+     * @return an int that matches one of the ProtoStream WIRE_TYPE_ constants
+     */
+    public int getWireType() {
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            // mWireType got overwritten when STATE_READING_PACKED was set. Send length delimited
+            // constant instead
+            return WIRE_TYPE_LENGTH_DELIMITED;
+        }
+        return mWireType;
+    }
+
+    /**
+     * Get the current offset in the proto binary.
+     */
+    public int getOffset() {
+        return mOffset + mDiscardedBytes;
+    }
+
+    /**
+     * Reads the tag of the next field from the stream. If previous field value was not read, its
+     * data will be skipped over.
+     *
+     * @return the field number of the next field
+     * @throws IOException if an I/O error occurs
+     */
+    public int nextField() throws IOException {
+
+        if ((mState & STATE_FIELD_MISS) == STATE_FIELD_MISS) {
+            // Data from the last nextField was not used, reuse the info
+            mState &= ~STATE_FIELD_MISS;
+            return mFieldNumber;
+        }
+        if ((mState & STATE_STARTED_FIELD_READ) == STATE_STARTED_FIELD_READ) {
+            // Field data was not read, skip to the next field
+            skip();
+            mState &= ~STATE_STARTED_FIELD_READ;
+        }
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            if (getOffset() < mPackedEnd) {
+                // In the middle of a packed field, return the same tag until last packed value
+                // has been read
+                mState |= STATE_STARTED_FIELD_READ;
+                return mFieldNumber;
+            } else if (getOffset() == mPackedEnd) {
+                // Reached the end of the packed field
+                mState &= ~STATE_READING_PACKED;
+            } else {
+                throw new ProtoParseException(
+                        "Unexpectedly reached end of packed field at offset 0x"
+                                + Integer.toHexString(mPackedEnd)
+                                + dumpDebugData());
+            }
+        }
+
+        if ((mDepth >= 0) && (getOffset() == getOffsetFromToken(
+                mExpectedObjectTokenStack.get(mDepth)))) {
+            // reached end of a embedded message
+            mFieldNumber = NO_MORE_FIELDS;
+        } else {
+            readTag();
+        }
+        return mFieldNumber;
+    }
+
+    /**
+     * Attempt to guess the next field. If there is a match, the field data will be ready to read.
+     * If there is no match, nextField will need to be called to get the field number
+     *
+     * @return true if fieldId matches the next field, false if not
+     */
+    public boolean isNextField(long fieldId) throws IOException {
+        if (nextField() == (int) fieldId) {
+            return true;
+        }
+        // Note to reuse the info from the nextField call in the next call.
+        mState |= STATE_FIELD_MISS;
+        return false;
+    }
+
+    /**
+     * Read a single double.
+     * Will throw if the current wire type is not fixed64
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public double readDouble(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        double value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_DOUBLE >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED64);
+                value = Double.longBitsToDouble(readFixed64());
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId)
+                                + ") cannot be read as a double"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single float.
+     * Will throw if the current wire type is not fixed32
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public float readFloat(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        float value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FLOAT >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED32);
+                value = Float.intBitsToFloat(readFixed32());
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not a float"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 32bit or varint proto type field as an int.
+     * Will throw if the current wire type is not varint or fixed32
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public int readInt(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        int value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FIXED32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_SFIXED32 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED32);
+                value = readFixed32();
+                break;
+            case (int) (FIELD_TYPE_SINT32 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = decodeZigZag32((int) readVarint());
+                break;
+            case (int) (FIELD_TYPE_INT32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_UINT32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_ENUM >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = (int) readVarint();
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an int"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 64bit or varint proto type field as an long.
+     *
+     * @param fieldId - must match the current field number
+     */
+    public long readLong(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        long value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FIXED64 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_SFIXED64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED64);
+                value = readFixed64();
+                break;
+            case (int) (FIELD_TYPE_SINT64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = decodeZigZag64(readVarint());
+                break;
+            case (int) (FIELD_TYPE_INT64 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_UINT64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = readVarint();
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an long"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 32bit or varint proto type field as an boolean.
+     *
+     * @param fieldId - must match the current field number
+     */
+    public boolean readBoolean(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        boolean value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_BOOL >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = readVarint() != 0;
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an boolean"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a string field
+     *
+     * @param fieldId - must match the current field number
+     */
+    public String readString(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+
+        String value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_STRING >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+                int len = (int) readVarint();
+                value = readRawString(len);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id(" + getFieldIdString(fieldId)
+                                + ") is not an string"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a bytes field
+     *
+     * @param fieldId - must match the current field number
+     */
+    public byte[] readBytes(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+
+        byte[] value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_MESSAGE >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_BYTES >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+                int len = (int) readVarint();
+                value = readRawBytes(len);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field type (" + getFieldIdString(fieldId)
+                                + ") cannot be read as raw bytes"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Start the read of an embedded Object
+     *
+     * @param fieldId - must match the current field number
+     * @return a token. The token must be handed back when finished reading embedded Object
+     */
+    public long start(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+
+        int messageSize = (int) readVarint();
+
+        if (mExpectedObjectTokenStack == null) {
+            mExpectedObjectTokenStack = new ArrayList<>();
+        }
+        if (++mDepth == mExpectedObjectTokenStack.size()) {
+            // Create a token to keep track of nested Object and extend the object stack
+            mExpectedObjectTokenStack.add(makeToken(0,
+                    (fieldId & FIELD_COUNT_REPEATED) == FIELD_COUNT_REPEATED, mDepth,
+                    (int) fieldId, getOffset() + messageSize));
+
+        } else {
+            // Create a token to keep track of nested Object
+            mExpectedObjectTokenStack.set(mDepth, makeToken(0,
+                    (fieldId & FIELD_COUNT_REPEATED) == FIELD_COUNT_REPEATED, mDepth,
+                    (int) fieldId, getOffset() + messageSize));
+        }
+
+        // Sanity check
+        if (mDepth > 0
+                && getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth))
+                > getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth - 1))) {
+            throw new ProtoParseException("Embedded Object ("
+                    + token2String(mExpectedObjectTokenStack.get(mDepth))
+                    + ") ends after of parent Objects's ("
+                    + token2String(mExpectedObjectTokenStack.get(mDepth - 1))
+                    + ") end"
+                    + dumpDebugData());
+        }
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return mExpectedObjectTokenStack.get(mDepth);
+    }
+
+    /**
+     * Note the end of a nested object. Must be called to continue streaming the rest of the proto.
+     * end can be called mid object parse. The offset will be moved to the next field outside the
+     * object.
+     *
+     * @param token - token
+     */
+    public void end(long token) {
+        // Sanity check to make sure user is keeping track of their embedded messages
+        if (mExpectedObjectTokenStack.get(mDepth) != token) {
+            throw new ProtoParseException(
+                    "end token " + token + " does not match current message token "
+                            + mExpectedObjectTokenStack.get(mDepth)
+                            + dumpDebugData());
+        }
+        if (getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth)) > getOffset()) {
+            // Did not read all of the message, skip to the end
+            incOffset(getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth)) - getOffset());
+        }
+        mDepth--;
+        mState &= ~STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Read the tag at the start of the next field and collect field number and wire type.
+     * Will set mFieldNumber to NO_MORE_FIELDS if end of buffer/stream reached.
+     */
+    private void readTag() throws IOException {
+        fillBuffer();
+        if (mOffset >= mEnd) {
+            // reached end of the stream
+            mFieldNumber = NO_MORE_FIELDS;
+            return;
+        }
+        int tag = (int) readVarint();
+        mFieldNumber = tag >>> FIELD_ID_SHIFT;
+        mWireType = tag & WIRE_TYPE_MASK;
+        mState |= STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Decode a 32 bit ZigZag encoded signed int.
+     *
+     * @param n - int to decode
+     * @return the decoded signed int
+     */
+    public int decodeZigZag32(final int n) {
+        return (n >>> 1) ^ -(n & 1);
+    }
+
+    /**
+     * Decode a 64 bit ZigZag encoded signed long.
+     *
+     * @param n - long to decode
+     * @return the decoded signed long
+     */
+    public long decodeZigZag64(final long n) {
+        return (n >>> 1) ^ -(n & 1);
+    }
+
+    /**
+     * Read a varint from the buffer
+     *
+     * @return the varint as a long
+     */
+    private long readVarint() throws IOException {
+        long value = 0;
+        int shift = 0;
+        while (true) {
+            fillBuffer();
+            // Limit how much bookkeeping is done by checking how far away the end of the buffer is
+            // and directly accessing buffer up until the end.
+            final int fragment = mEnd - mOffset;
+            for (int i = 0; i < fragment; i++) {
+                byte b = mBuffer[(mOffset + i)];
+                value |= (b & 0x7FL) << shift;
+                if ((b & 0x80) == 0) {
+                    incOffset(i + 1);
+                    return value;
+                }
+                shift += 7;
+                if (shift > 63) {
+                    throw new ProtoParseException(
+                            "Varint is too large at offset 0x"
+                                    + Integer.toHexString(getOffset() + i)
+                                    + dumpDebugData());
+                }
+            }
+            // Hit the end of the buffer, do some incrementing and checking, then continue
+            incOffset(fragment);
+        }
+    }
+
+    /**
+     * Read a fixed 32 bit int from the buffer
+     *
+     * @return the fixed32 as a int
+     */
+    private int readFixed32() throws IOException {
+        // check for fast path, which is likely with a reasonable buffer size
+        if (mOffset + 4 <= mEnd) {
+            // don't bother filling buffer since we know the end is plenty far away
+            incOffset(4);
+            return (mBuffer[mOffset - 4] & 0xFF)
+                    | ((mBuffer[mOffset - 3] & 0xFF) << 8)
+                    | ((mBuffer[mOffset - 2] & 0xFF) << 16)
+                    | ((mBuffer[mOffset - 1] & 0xFF) << 24);
+        }
+
+        // the Fixed32 crosses the edge of a chunk, read the Fixed32 in multiple fragments.
+        // There will be two fragment reads except when the chunk size is 2 or less.
+        int value = 0;
+        int shift = 0;
+        int bytesLeft = 4;
+        while (bytesLeft > 0) {
+            fillBuffer();
+            // Find the number of bytes available until the end of the chunk or Fixed32
+            int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft;
+            incOffset(fragment);
+            bytesLeft -= fragment;
+            while (fragment > 0) {
+                value |= ((mBuffer[mOffset - fragment] & 0xFF) << shift);
+                fragment--;
+                shift += 8;
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Read a fixed 64 bit long from the buffer
+     *
+     * @return the fixed64 as a long
+     */
+    private long readFixed64() throws IOException {
+        // check for fast path, which is likely with a reasonable buffer size
+        if (mOffset + 8 <= mEnd) {
+            // don't bother filling buffer since we know the end is plenty far away
+            incOffset(8);
+            return (mBuffer[mOffset - 8] & 0xFFL)
+                    | ((mBuffer[mOffset - 7] & 0xFFL) << 8)
+                    | ((mBuffer[mOffset - 6] & 0xFFL) << 16)
+                    | ((mBuffer[mOffset - 5] & 0xFFL) << 24)
+                    | ((mBuffer[mOffset - 4] & 0xFFL) << 32)
+                    | ((mBuffer[mOffset - 3] & 0xFFL) << 40)
+                    | ((mBuffer[mOffset - 2] & 0xFFL) << 48)
+                    | ((mBuffer[mOffset - 1] & 0xFFL) << 56);
+        }
+
+        // the Fixed64 crosses the edge of a chunk, read the Fixed64 in multiple fragments.
+        // There will be two fragment reads except when the chunk size is 6 or less.
+        long value = 0;
+        int shift = 0;
+        int bytesLeft = 8;
+        while (bytesLeft > 0) {
+            fillBuffer();
+            // Find the number of bytes available until the end of the chunk or Fixed64
+            int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft;
+            incOffset(fragment);
+            bytesLeft -= fragment;
+            while (fragment > 0) {
+                value |= ((mBuffer[(mOffset - fragment)] & 0xFFL) << shift);
+                fragment--;
+                shift += 8;
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Read raw bytes from the buffer
+     *
+     * @param n - number of bytes to read
+     * @return a byte array with raw bytes
+     */
+    private byte[] readRawBytes(int n) throws IOException {
+        byte[] buffer = new byte[n];
+        int pos = 0;
+        while (mOffset + n - pos > mEnd) {
+            int fragment = mEnd - mOffset;
+            if (fragment > 0) {
+                System.arraycopy(mBuffer, mOffset, buffer, pos, fragment);
+                incOffset(fragment);
+                pos += fragment;
+            }
+            fillBuffer();
+            if (mOffset >= mEnd) {
+                throw new ProtoParseException(
+                        "Unexpectedly reached end of the InputStream at offset 0x"
+                                + Integer.toHexString(mEnd)
+                                + dumpDebugData());
+            }
+        }
+        System.arraycopy(mBuffer, mOffset, buffer, pos, n - pos);
+        incOffset(n - pos);
+        return buffer;
+    }
+
+    /**
+     * Read raw string from the buffer
+     *
+     * @param n - number of bytes to read
+     * @return a string
+     */
+    private String readRawString(int n) throws IOException {
+        fillBuffer();
+        if (mOffset + n <= mEnd) {
+            // fast path read. String is well within the current buffer
+            String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
+                    StandardCharsets.UTF_8);
+            incOffset(n);
+            return value;
+        } else if (n <= mBufferSize) {
+            // String extends past buffer, but can be encapsulated in a buffer. Copy the first chunk
+            // of the string to the start of the buffer and then fill the rest of the buffer from
+            // the stream.
+            final int stringHead = mEnd - mOffset;
+            System.arraycopy(mBuffer, mOffset, mBuffer, 0, stringHead);
+            mEnd = stringHead + mStream.read(mBuffer, stringHead, n - stringHead);
+
+            mDiscardedBytes += mOffset;
+            mOffset = 0;
+
+            String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
+                    StandardCharsets.UTF_8);
+            incOffset(n);
+            return value;
+        }
+        // Otherwise, the string is too large to use the buffer. Create the string from a
+        // separate byte array.
+        return StringFactory.newStringFromBytes(readRawBytes(n), 0, n, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Fill the buffer with a chunk from the stream if need be.
+     * Will skip chunks until mOffset is reached
+     */
+    private void fillBuffer() throws IOException {
+        if (mOffset >= mEnd && mStream != null) {
+            mOffset -= mEnd;
+            mDiscardedBytes += mEnd;
+            if (mOffset >= mBufferSize) {
+                int skipped = (int) mStream.skip((mOffset / mBufferSize) * mBufferSize);
+                mDiscardedBytes += skipped;
+                mOffset -= skipped;
+            }
+            mEnd = mStream.read(mBuffer);
+        }
+    }
+
+    /**
+     * Skips the rest of current field and moves to the start of the next field. This should only be
+     * called while state is STATE_STARTED_FIELD_READ
+     */
+    public void skip() throws IOException {
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            incOffset(mPackedEnd - getOffset());
+        } else {
+            switch (mWireType) {
+                case WIRE_TYPE_VARINT:
+                    byte b;
+                    do {
+                        fillBuffer();
+                        b = mBuffer[mOffset];
+                        incOffset(1);
+                    } while ((b & 0x80) != 0);
+                    break;
+                case WIRE_TYPE_FIXED64:
+                    incOffset(8);
+                    break;
+                case WIRE_TYPE_LENGTH_DELIMITED:
+                    fillBuffer();
+                    int length = (int) readVarint();
+                    incOffset(length);
+                    break;
+                /*
+            case WIRE_TYPE_START_GROUP:
+                // Not implemented
+                break;
+            case WIRE_TYPE_END_GROUP:
+                // Not implemented
+                break;
+                */
+                case WIRE_TYPE_FIXED32:
+                    incOffset(4);
+                    break;
+                default:
+                    throw new ProtoParseException(
+                            "Unexpected wire type: " + mWireType + " at offset 0x"
+                                    + Integer.toHexString(mOffset)
+                                    + dumpDebugData());
+            }
+        }
+        mState &= ~STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Increment the offset and handle all the relevant bookkeeping
+     * Refilling the buffer when its end is reached will be handled elsewhere (ideally just before
+     * a read, to avoid unnecessary reads from stream)
+     *
+     * @param n - number of bytes to increment
+     */
+    private void incOffset(int n) {
+        mOffset += n;
+
+        if (mDepth >= 0 && getOffset() > getOffsetFromToken(
+                mExpectedObjectTokenStack.get(mDepth))) {
+            throw new ProtoParseException("Unexpectedly reached end of embedded object.  "
+                    + token2String(mExpectedObjectTokenStack.get(mDepth))
+                    + dumpDebugData());
+        }
+    }
+
+    /**
+     * Check the current wire type to determine if current numeric field is packed. If it is packed,
+     * set up to deal with the field
+     * This should only be called for primitive numeric field types.
+     *
+     * @param fieldId - used to determine what the packed wire type is.
+     */
+    private void checkPacked(long fieldId) throws IOException {
+        if (mWireType == WIRE_TYPE_LENGTH_DELIMITED) {
+            // Primitive Field is length delimited, must be a packed field.
+            final int length = (int) readVarint();
+            mPackedEnd = getOffset() + length;
+            mState |= STATE_READING_PACKED;
+
+            // Fake the wire type, based on the field type
+            switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                    >>> FIELD_TYPE_SHIFT)) {
+                case (int) (FIELD_TYPE_FLOAT >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_FIXED32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SFIXED32 >>> FIELD_TYPE_SHIFT):
+                    if (length % 4 != 0) {
+                        throw new IllegalArgumentException(
+                                "Requested field id (" + getFieldIdString(fieldId)
+                                        + ") packed length " + length
+                                        + " is not aligned for fixed32"
+                                        + dumpDebugData());
+                    }
+                    mWireType = WIRE_TYPE_FIXED32;
+                    break;
+                case (int) (FIELD_TYPE_DOUBLE >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_FIXED64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SFIXED64 >>> FIELD_TYPE_SHIFT):
+                    if (length % 8 != 0) {
+                        throw new IllegalArgumentException(
+                                "Requested field id (" + getFieldIdString(fieldId)
+                                        + ") packed length " + length
+                                        + " is not aligned for fixed64"
+                                        + dumpDebugData());
+                    }
+                    mWireType = WIRE_TYPE_FIXED64;
+                    break;
+                case (int) (FIELD_TYPE_SINT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_INT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_UINT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SINT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_INT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_UINT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_ENUM >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_BOOL >>> FIELD_TYPE_SHIFT):
+                    mWireType = WIRE_TYPE_VARINT;
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Requested field id (" + getFieldIdString(fieldId)
+                                    + ") is not a packable field"
+                                    + dumpDebugData());
+            }
+        }
+    }
+
+
+    /**
+     * Check a field id constant against current field number
+     *
+     * @param fieldId - throws if fieldId does not match mFieldNumber
+     */
+    private void assertFieldNumber(long fieldId) {
+        if ((int) fieldId != mFieldNumber) {
+            throw new IllegalArgumentException("Requested field id (" + getFieldIdString(fieldId)
+                    + ") does not match current field number (0x" + Integer.toHexString(
+                    mFieldNumber)
+                    + ") at offset 0x" + Integer.toHexString(getOffset())
+                    + dumpDebugData());
+        }
+    }
+
+
+    /**
+     * Check a wire type against current wire type.
+     *
+     * @param wireType - throws if wireType does not match mWireType.
+     */
+    private void assertWireType(int wireType) {
+        if (wireType != mWireType) {
+            throw new WireTypeMismatchException(
+                    "Current wire type " + getWireTypeString(mWireType)
+                            + " does not match expected wire type " + getWireTypeString(wireType)
+                            + " at offset 0x" + Integer.toHexString(getOffset())
+                            + dumpDebugData());
+        }
+    }
+
+    /**
+     * Check if there is data ready to be read.
+     */
+    private void assertFreshData() {
+        if ((mState & STATE_STARTED_FIELD_READ) != STATE_STARTED_FIELD_READ) {
+            throw new ProtoParseException(
+                    "Attempting to read already read field at offset 0x" + Integer.toHexString(
+                            getOffset()) + dumpDebugData());
+        }
+    }
+
+    /**
+     * Dump debugging data about the buffer.
+     */
+    public String dumpDebugData() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("\nmFieldNumber : 0x" + Integer.toHexString(mFieldNumber));
+        sb.append("\nmWireType : 0x" + Integer.toHexString(mWireType));
+        sb.append("\nmState : 0x" + Integer.toHexString(mState));
+        sb.append("\nmDiscardedBytes : 0x" + Integer.toHexString(mDiscardedBytes));
+        sb.append("\nmOffset : 0x" + Integer.toHexString(mOffset));
+        sb.append("\nmExpectedObjectTokenStack : ");
+        if (mExpectedObjectTokenStack == null) {
+            sb.append("null");
+        } else {
+            sb.append(mExpectedObjectTokenStack);
+        }
+        sb.append("\nmDepth : 0x" + Integer.toHexString(mDepth));
+        sb.append("\nmBuffer : ");
+        if (mBuffer == null) {
+            sb.append("null");
+        } else {
+            sb.append(mBuffer);
+        }
+        sb.append("\nmBufferSize : 0x" + Integer.toHexString(mBufferSize));
+        sb.append("\nmEnd : 0x" + Integer.toHexString(mEnd));
+
+        return sb.toString();
+    }
+}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index a94806a..a1ee61c 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -100,88 +100,12 @@
  * errors if they are not matched.
  */
 @TestApi
-public final class ProtoOutputStream {
+public final class ProtoOutputStream extends ProtoStream {
+    /**
+     * @hide
+     */
     public static final String TAG = "ProtoOutputStream";
 
-    public static final int FIELD_ID_SHIFT = 3;
-    public static final int WIRE_TYPE_MASK = (1<<FIELD_ID_SHIFT)-1;
-    public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
-
-    public static final int WIRE_TYPE_VARINT = 0;
-    public static final int WIRE_TYPE_FIXED64 = 1;
-    public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
-    public static final int WIRE_TYPE_START_GROUP = 3;
-    public static final int WIRE_TYPE_END_GROUP = 4;
-    public static final int WIRE_TYPE_FIXED32 = 5;
-
-    /**
-     * Position of the field type in a (long) fieldId.
-     */
-    public static final int FIELD_TYPE_SHIFT = 32;
-
-    /**
-     * Mask for the field types stored in a fieldId.  Leaves a whole
-     * byte for future expansion, even though there are currently only 17 types.
-     */
-    public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
-
-    public static final long FIELD_TYPE_UNKNOWN = 0;
-
-    /**
-     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
-     * so no extra mapping needs to be maintained in this case.
-     */
-    public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
-//  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
-    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
-
-    private static final String[] FIELD_TYPE_NAMES = new String[] {
-        "Double",
-        "Float",
-        "Int64",
-        "UInt64",
-        "Int32",
-        "Fixed64",
-        "Fixed32",
-        "Bool",
-        "String",
-        "Group",  // This field is deprecated but reserved here for indexing.
-        "Message",
-        "Bytes",
-        "UInt32",
-        "Enum",
-        "SFixed32",
-        "SFixed64",
-        "SInt32",
-        "SInt64",
-    };
-
-    //
-    // FieldId flags for whether the field is single, repeated or packed.
-    //
-    public static final int FIELD_COUNT_SHIFT = 40;
-    public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
-
-    public static final long FIELD_COUNT_UNKNOWN = 0;
-    public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
-    public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
-    public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
-
     /**
      * Our buffer.
      */
@@ -1997,94 +1921,6 @@
         }
     }
 
-    //
-    // Child objects
-    //
-
-    /**
-     * Make a token.
-     *  Bits 61-63 - tag size (So we can go backwards later if the object had not data)
-     *                - 3 bits, max value 7, max value needed 5
-     *  Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
-     *  Bits 59-51 - depth (For error checking)
-     *                - 9 bits, max value 512, when checking, value is masked (if we really
-     *                  are more than 512 levels deep)
-     *  Bits 32-50 - objectId (For error checking)
-     *                - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
-     *                  because of the overflow, and only the tokens are compared.
-     *  Bits  0-31 - offset of the first size field in the buffer.
-     */
-    // VisibleForTesting
-    public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
-            int sizePos) {
-        return ((0x07L & (long)tagSize) << 61)
-                | (repeated ? (1L << 60) : 0)
-                | (0x01ffL & (long)depth) << 51
-                | (0x07ffffL & (long)objectId) << 32
-                | (0x0ffffffffL & (long)sizePos);
-    }
-
-    /**
-     * Get the encoded tag size from the token.
-     */
-    public static int getTagSizeFromToken(long token) {
-        return (int)(0x7 & (token >> 61));
-    }
-
-    /**
-     * Get whether this is a call to startObject (false) or startRepeatedObject (true).
-     */
-    public static boolean getRepeatedFromToken(long token) {
-        return (0x1 & (token >> 60)) != 0;
-    }
-
-    /**
-     * Get the nesting depth of startObject calls from the token.
-     */
-    public static int getDepthFromToken(long token) {
-        return (int)(0x01ff & (token >> 51));
-    }
-
-    /**
-     * Get the object ID from the token. The object ID is a serial number for the
-     * startObject calls that have happened on this object.  The values are truncated
-     * to 9 bits, but that is sufficient for error checking.
-     */
-    public static int getObjectIdFromToken(long token) {
-        return (int)(0x07ffff & (token >> 32));
-    }
-
-    /**
-     * Get the location of the childRawSize (the first 32 bit size field) in this object.
-     */
-    public static int getSizePosFromToken(long token) {
-        return (int)token;
-    }
-
-    /**
-     * Convert the object ID to the ordinal value -- the n-th call to startObject.
-     * The object IDs start at -1 and count backwards, so that the value is unlikely
-     * to alias with an actual size field that had been written.
-     */
-    public static int convertObjectIdToOrdinal(int objectId) {
-        return (-1 & 0x07ffff) - objectId;
-    }
-
-    /**
-     * Return a debugging string of a token.
-     */
-    public static String token2String(long token) {
-        if (token == 0L) {
-            return "Token(0)";
-        } else {
-            return "Token(val=0x" + Long.toHexString(token)
-                    + " depth=" + getDepthFromToken(token)
-                    + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
-                    + " tagSize=" + getTagSizeFromToken(token)
-                    + " sizePos=" + getSizePosFromToken(token)
-                    + ')';
-        }
-    }
 
     /**
      * Start a child object.
@@ -2175,7 +2011,7 @@
         // at which to write the size.
         final int depth = getDepthFromToken(token);
         final boolean expectedRepeated = getRepeatedFromToken(token);
-        final int sizePos = getSizePosFromToken(token);
+        final int sizePos = getOffsetFromToken(token);
         final int childRawSize = mBuffer.getWritePos() - sizePos - 8;
 
         if (repeated != expectedRepeated) {
@@ -2346,56 +2182,6 @@
     }
 
     /**
-     * Get the developer-usable name of a field type.
-     */
-    private static String getFieldTypeString(long fieldType) {
-        int index = ((int)((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
-        if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
-            return FIELD_TYPE_NAMES[index];
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get the developer-usable name of a field count.
-     */
-    private static String getFieldCountString(long fieldCount) {
-        if (fieldCount == FIELD_COUNT_SINGLE) {
-            return "";
-        } else if (fieldCount == FIELD_COUNT_REPEATED) {
-            return "Repeated";
-        } else if (fieldCount == FIELD_COUNT_PACKED) {
-            return "Packed";
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get a debug string for a fieldId.
-     */
-    private String getFieldIdString(long fieldId) {
-        final long fieldCount = fieldId & FIELD_COUNT_MASK;
-        String countString = getFieldCountString(fieldCount);
-        if (countString == null) {
-            countString = "fieldCount=" + fieldCount;
-        }
-        if (countString.length() > 0) {
-            countString += " ";
-        }
-
-        final long fieldType = fieldId & FIELD_TYPE_MASK;
-        String typeString = getFieldTypeString(fieldType);
-        if (typeString == null) {
-            typeString = "fieldType=" + fieldType;
-        }
-
-        return countString + typeString + " tag=" + ((int) fieldId)
-                + " fieldId=0x" + Long.toHexString(fieldId);
-    }
-
-    /**
      * Return how many bytes an encoded field tag will require.
      */
     private static int getTagSize(int id) {
diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java
new file mode 100644
index 0000000..9e2e95a
--- /dev/null
+++ b/core/java/android/util/proto/ProtoStream.java
@@ -0,0 +1,280 @@
+/*
+ * 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.util.proto;
+
+import android.annotation.TestApi;
+
+/**
+ * Abstract base class for both protobuf streams.
+ *
+ * Contains a set of useful constants and methods used by both
+ * ProtoOutputStream and ProtoInputStream
+ *
+ * @hide
+ */
+@TestApi
+public abstract class ProtoStream {
+
+    public static final int FIELD_ID_SHIFT = 3;
+    public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
+    public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
+
+    public static final int WIRE_TYPE_VARINT = 0;
+    public static final int WIRE_TYPE_FIXED64 = 1;
+    public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
+    public static final int WIRE_TYPE_START_GROUP = 3;
+    public static final int WIRE_TYPE_END_GROUP = 4;
+    public static final int WIRE_TYPE_FIXED32 = 5;
+
+    /**
+     * Position of the field type in a (long) fieldId.
+     */
+    public static final int FIELD_TYPE_SHIFT = 32;
+
+    /**
+     * Mask for the field types stored in a fieldId.  Leaves a whole
+     * byte for future expansion, even though there are currently only 17 types.
+     */
+    public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
+
+    public static final long FIELD_TYPE_UNKNOWN = 0;
+
+    /**
+     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+     * so no extra mapping needs to be maintained in this case.
+     */
+    public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+    //  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
+
+    protected static final String[] FIELD_TYPE_NAMES = new String[]{
+            "Double",
+            "Float",
+            "Int64",
+            "UInt64",
+            "Int32",
+            "Fixed64",
+            "Fixed32",
+            "Bool",
+            "String",
+            "Group",  // This field is deprecated but reserved here for indexing.
+            "Message",
+            "Bytes",
+            "UInt32",
+            "Enum",
+            "SFixed32",
+            "SFixed64",
+            "SInt32",
+            "SInt64",
+    };
+
+    //
+    // FieldId flags for whether the field is single, repeated or packed.
+    //
+    public static final int FIELD_COUNT_SHIFT = 40;
+    public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
+
+    public static final long FIELD_COUNT_UNKNOWN = 0;
+    public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+    public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+    public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
+
+
+    /**
+     * Get the developer-usable name of a field type.
+     */
+    public static String getFieldTypeString(long fieldType) {
+        int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
+        if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
+            return FIELD_TYPE_NAMES[index];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the developer-usable name of a field count.
+     */
+    public static String getFieldCountString(long fieldCount) {
+        if (fieldCount == FIELD_COUNT_SINGLE) {
+            return "";
+        } else if (fieldCount == FIELD_COUNT_REPEATED) {
+            return "Repeated";
+        } else if (fieldCount == FIELD_COUNT_PACKED) {
+            return "Packed";
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the developer-usable name of a wire type.
+     */
+    public static String getWireTypeString(int wireType) {
+        switch (wireType) {
+            case WIRE_TYPE_VARINT:
+                return "Varint";
+            case WIRE_TYPE_FIXED64:
+                return "Fixed64";
+            case WIRE_TYPE_LENGTH_DELIMITED:
+                return "Length Delimited";
+            case WIRE_TYPE_START_GROUP:
+                return "Start Group";
+            case WIRE_TYPE_END_GROUP:
+                return "End Group";
+            case WIRE_TYPE_FIXED32:
+                return "Fixed32";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Get a debug string for a fieldId.
+     */
+    public static String getFieldIdString(long fieldId) {
+        final long fieldCount = fieldId & FIELD_COUNT_MASK;
+        String countString = getFieldCountString(fieldCount);
+        if (countString == null) {
+            countString = "fieldCount=" + fieldCount;
+        }
+        if (countString.length() > 0) {
+            countString += " ";
+        }
+
+        final long fieldType = fieldId & FIELD_TYPE_MASK;
+        String typeString = getFieldTypeString(fieldType);
+        if (typeString == null) {
+            typeString = "fieldType=" + fieldType;
+        }
+
+        return countString + typeString + " tag=" + ((int) fieldId)
+                + " fieldId=0x" + Long.toHexString(fieldId);
+    }
+
+    /**
+     * Combine a fieldId (the field keys in the proto file) and the field flags.
+     * Mostly useful for testing because the generated code contains the fieldId
+     * constants.
+     */
+    public static long makeFieldId(int id, long fieldFlags) {
+        return fieldFlags | (((long) id) & 0x0ffffffffL);
+    }
+
+    //
+    // Child objects
+    //
+
+    /**
+     * Make a token.
+     * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
+     *            - 3 bits, max value 7, max value needed 5
+     * Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
+     * Bits 59-51 - depth (For error checking)
+     *            - 9 bits, max value 512, when checking, value is masked (if we really
+     *              are more than 512 levels deep)
+     * Bits 32-50 - objectId (For error checking)
+     *            - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
+     *              because of the overflow, and only the tokens are compared.
+     * Bits  0-31 - offset of interest for the object.
+     */
+    public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
+            int offset) {
+        return ((0x07L & (long) tagSize) << 61)
+                | (repeated ? (1L << 60) : 0)
+                | (0x01ffL & (long) depth) << 51
+                | (0x07ffffL & (long) objectId) << 32
+                | (0x0ffffffffL & (long) offset);
+    }
+
+    /**
+     * Get the encoded tag size from the token.
+     */
+    public static int getTagSizeFromToken(long token) {
+        return (int) (0x7 & (token >> 61));
+    }
+
+    /**
+     * Get whether this is a call to startObject (false) or startRepeatedObject (true).
+     */
+    public static boolean getRepeatedFromToken(long token) {
+        return (0x1 & (token >> 60)) != 0;
+    }
+
+    /**
+     * Get the nesting depth of startObject calls from the token.
+     */
+    public static int getDepthFromToken(long token) {
+        return (int) (0x01ff & (token >> 51));
+    }
+
+    /**
+     * Get the object ID from the token. The object ID is a serial number for the
+     * startObject calls that have happened on this object.  The values are truncated
+     * to 9 bits, but that is sufficient for error checking.
+     */
+    public static int getObjectIdFromToken(long token) {
+        return (int) (0x07ffff & (token >> 32));
+    }
+
+    /**
+     * Get the location of the offset recorded in the token.
+     */
+    public static int getOffsetFromToken(long token) {
+        return (int) token;
+    }
+
+    /**
+     * Convert the object ID to the ordinal value -- the n-th call to startObject.
+     * The object IDs start at -1 and count backwards, so that the value is unlikely
+     * to alias with an actual size field that had been written.
+     */
+    public static int convertObjectIdToOrdinal(int objectId) {
+        return (-1 & 0x07ffff) - objectId;
+    }
+
+    /**
+     * Return a debugging string of a token.
+     */
+    public static String token2String(long token) {
+        if (token == 0L) {
+            return "Token(0)";
+        } else {
+            return "Token(val=0x" + Long.toHexString(token)
+                    + " depth=" + getDepthFromToken(token)
+                    + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
+                    + " tagSize=" + getTagSizeFromToken(token)
+                    + " offset=" + getOffsetFromToken(token)
+                    + ')';
+        }
+    }
+}
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index c7bbb9f..03bf590 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -19,6 +19,8 @@
 import android.util.AggStats;
 import android.util.Duration;
 
+import java.io.IOException;
+
 /**
  * This class contains a list of helper functions to write common proto in
  * //frameworks/base/core/proto/android/base directory
@@ -70,4 +72,54 @@
             }
         }
     }
+
+    /**
+     * Provide debug data about the current field as a string
+     */
+    public static String currentFieldToString(ProtoInputStream proto) throws IOException {
+        StringBuilder sb = new StringBuilder();
+
+        final int fieldNumber = proto.getFieldNumber();
+        final int wireType = proto.getWireType();
+        long fieldConstant;
+
+        sb.append("Offset : 0x" + Integer.toHexString(proto.getOffset()));
+        sb.append("\nField Number : 0x" + Integer.toHexString(proto.getFieldNumber()));
+        sb.append("\nWire Type : ");
+        switch (wireType) {
+            case ProtoStream.WIRE_TYPE_VARINT:
+                sb.append("varint");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64);
+                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                break;
+            case ProtoStream.WIRE_TYPE_FIXED64:
+                sb.append("fixed64");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64);
+                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                break;
+            case ProtoStream.WIRE_TYPE_LENGTH_DELIMITED:
+                sb.append("length delimited");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES);
+                sb.append("\nField Bytes : " + proto.readBytes(fieldConstant));
+                break;
+            case ProtoStream.WIRE_TYPE_START_GROUP:
+                sb.append("start group");
+                break;
+            case ProtoStream.WIRE_TYPE_END_GROUP:
+                sb.append("end group");
+                break;
+            case ProtoStream.WIRE_TYPE_FIXED32:
+                sb.append("fixed32");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32);
+                sb.append("\nField Value : 0x" + Integer.toHexString(proto.readInt(fieldConstant)));
+                break;
+            default:
+                sb.append("unknown(" + proto.getWireType() + ")");
+        }
+        return sb.toString();
+    }
 }
diff --git a/core/java/android/util/proto/WireTypeMismatchException.java b/core/java/android/util/proto/WireTypeMismatchException.java
new file mode 100644
index 0000000..d90b4f8
--- /dev/null
+++ b/core/java/android/util/proto/WireTypeMismatchException.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.proto;
+
+import android.annotation.TestApi;
+
+/**
+ * Thrown when there is an error parsing protobuf data.
+ *
+ * @hide
+ */
+@TestApi
+public class WireTypeMismatchException extends ProtoParseException {
+
+    /**
+     * Construct a WireTypeMismatchException.
+     *
+     * @param msg The message.
+     */
+    public WireTypeMismatchException(String msg) {
+        super(msg);
+    }
+}
+
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 45fa561..eb41e07 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -32,6 +32,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.text.style.AccessibilityClickableSpan;
 import android.text.style.ClickableSpan;
 import android.util.LongSparseArray;
@@ -702,6 +703,14 @@
                     // Handle this hidden action separately
                     succeeded = handleClickableSpanActionUiThread(
                             target, virtualDescendantId, arguments);
+                } else if (action == R.id.accessibilityActionOutsideTouch) {
+                    // trigger ACTION_OUTSIDE to notify windows
+                    final long now = SystemClock.uptimeMillis();
+                    MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_OUTSIDE,
+                            0, 0, 0);
+                    event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+                    mViewRootImpl.dispatchInputEvent(event);
+                    succeeded = true;
                 } else {
                     AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
                     if (provider != null) {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index ce16ffc..a872776 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,6 +22,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -153,7 +154,7 @@
         public String toString() { return "FRAME_CALLBACK_TOKEN"; }
     };
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final Object mLock = new Object();
 
     private final Looper mLooper;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 8641d7f..c38fcf3 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.method.MetaKeyKeyListener;
@@ -1256,7 +1257,7 @@
 
     @UnsupportedAppUsage
     private int mDeviceId;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSource;
     private int mDisplayId;
     @UnsupportedAppUsage
@@ -1658,7 +1659,7 @@
      * @hide
      */
     @Override
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final void recycle() {
         super.recycle();
         mCharacters = null;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index c520a99..9aab419 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.LayoutRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
@@ -154,7 +155,9 @@
          * @return View Newly created view. Return null for the default
          *         behavior.
          */
-        public View onCreateView(String name, Context context, AttributeSet attrs);
+        @Nullable
+        View onCreateView(@NonNull String name, @NonNull Context context,
+                @NonNull AttributeSet attrs);
     }
 
     public interface Factory2 extends Factory {
@@ -172,7 +175,9 @@
          * @return View Newly created view. Return null for the default
          *         behavior.
          */
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
+        @Nullable
+        View onCreateView(@Nullable View parent, @NonNull String name,
+                @NonNull Context context, @NonNull AttributeSet attrs);
     }
 
     private static class FactoryMerger implements Factory2 {
@@ -186,13 +191,17 @@
             mF22 = f22;
         }
 
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
+        @Nullable
+        public View onCreateView(@NonNull String name, @NonNull Context context,
+                @NonNull AttributeSet attrs) {
             View v = mF1.onCreateView(name, context, attrs);
             if (v != null) return v;
             return mF2.onCreateView(name, context, attrs);
         }
 
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        @Nullable
+        public View onCreateView(@Nullable View parent, @NonNull String name,
+                @NonNull Context context, @NonNull AttributeSet attrs) {
             View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs)
                     : mF1.onCreateView(name, context, attrs);
             if (v != null) return v;
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index dc097a1..cf11fd0 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -146,7 +147,7 @@
     private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
     private static boolean sUseLargeIcons = false;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mType;
     private int mSystemIconResourceId;
     @UnsupportedAppUsage
@@ -319,7 +320,7 @@
      * @throws IllegalArgumentException if context is null.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public PointerIcon load(@NonNull Context context) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9bc53ed..c29fbbb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4582,7 +4582,7 @@
     /**
      * Object that handles automatic animation of view properties.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ViewPropertyAnimator mAnimator = null;
 
     /**
@@ -6876,7 +6876,7 @@
      * @param requestCode The request code to use.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void startActivityForResult(Intent intent, int requestCode) {
         mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this);
         getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null);
@@ -18406,7 +18406,7 @@
      * communicate with the window manager.
      * @return the session object to communicate with the window manager
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     /*package*/ IWindowSession getWindowSession() {
         return mAttachInfo != null ? mAttachInfo.mSession : null;
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0119d2e..1b3e62d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -8116,7 +8116,7 @@
         /**
          * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
          * to be done so that the new margins are taken into account. Left and right margins may be
-         * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
+         * overridden by {@link android.view.View#requestLayout()} depending on layout direction.
          * Margin values should be positive.
          *
          * @param left the left margin size
@@ -8146,8 +8146,8 @@
         /**
          * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
          * needs to be done so that the new relative margins are taken into account. Left and right
-         * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
-         * direction. Margin values should be positive.
+         * margins may be overridden by {@link android.view.View#requestLayout()} depending on
+         * layout direction. Margin values should be positive.
          *
          * @param start the start margin size
          * @param top the top margin size
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f436962..a7ec6df 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -422,7 +422,7 @@
          * @return boolean You must return true for the panel to be displayed;
          *         if you return false it will not be shown.
          */
-        public boolean onCreatePanelMenu(int featureId, Menu menu);
+        boolean onCreatePanelMenu(int featureId, @NonNull Menu menu);
 
         /**
          * Prepare a panel to be displayed.  This is called right before the
@@ -438,7 +438,7 @@
          *
          * @see #onCreatePanelView
          */
-        public boolean onPreparePanel(int featureId, View view, Menu menu);
+        boolean onPreparePanel(int featureId, @Nullable View view, @NonNull Menu menu);
 
         /**
          * Called when a panel's menu is opened by the user. This may also be
@@ -450,7 +450,7 @@
          * @return Return true to allow the menu to open, or false to prevent
          *         the menu from opening.
          */
-        public boolean onMenuOpened(int featureId, Menu menu);
+        boolean onMenuOpened(int featureId, @NonNull Menu menu);
 
         /**
          * Called when a panel's menu item has been selected by the user.
@@ -462,7 +462,7 @@
          *         false to perform the normal menu handling (calling its
          *         Runnable or sending a Message to its target Handler).
          */
-        public boolean onMenuItemSelected(int featureId, MenuItem item);
+        boolean onMenuItemSelected(int featureId, @NonNull MenuItem item);
 
         /**
          * This is called whenever the current window attributes change.
@@ -512,7 +512,7 @@
          * @param menu If onCreatePanelView() returned null, this is the Menu
          *            being displayed in the panel.
          */
-        public void onPanelClosed(int featureId, Menu menu);
+        void onPanelClosed(int featureId, @NonNull Menu menu);
 
         /**
          * Called when the user signals the desire to start a search.
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7bae28a..82e9a5c 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -49,6 +49,7 @@
     public CharSequence title;
     public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
     public boolean inPictureInPicture;
+    public boolean hasFlagWatchOutsideTouch;
 
     private WindowInfo() {
         /* do nothing - hide constructor */
@@ -74,6 +75,7 @@
         window.title = other.title;
         window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
         window.inPictureInPicture = other.inPictureInPicture;
+        window.hasFlagWatchOutsideTouch = other.hasFlagWatchOutsideTouch;
 
         if (other.childTokens != null && !other.childTokens.isEmpty()) {
             if (window.childTokens == null) {
@@ -108,6 +110,7 @@
         parcel.writeCharSequence(title);
         parcel.writeLong(accessibilityIdOfAnchor);
         parcel.writeInt(inPictureInPicture ? 1 : 0);
+        parcel.writeInt(hasFlagWatchOutsideTouch ? 1 : 0);
 
         if (childTokens != null && !childTokens.isEmpty()) {
             parcel.writeInt(1);
@@ -130,6 +133,8 @@
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
         builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
+        builder.append(", pictureInPicture=").append(inPictureInPicture);
+        builder.append(", watchOutsideTouch=").append(hasFlagWatchOutsideTouch);
         builder.append(']');
         return builder.toString();
     }
@@ -145,6 +150,7 @@
         title = parcel.readCharSequence();
         accessibilityIdOfAnchor = parcel.readLong();
         inPictureInPicture = (parcel.readInt() == 1);
+        hasFlagWatchOutsideTouch = (parcel.readInt() == 1);
 
         final boolean hasChildren = (parcel.readInt() == 1);
         if (hasChildren) {
@@ -167,6 +173,7 @@
             childTokens.clear();
         }
         inPictureInPicture = false;
+        hasFlagWatchOutsideTouch = false;
     }
 
     public static final Parcelable.Creator<WindowInfo> CREATOR =
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index d810067..4ca9a14 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -213,7 +214,7 @@
         }
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static IWindowSession peekWindowSession() {
         synchronized (WindowManagerGlobal.class) {
             return sWindowSession;
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 3eca854..dccf9d4 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -761,7 +762,7 @@
     private CharSequence mPackageName;
     private long mEventTime;
     int mMovementGranularity;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     int mAction;
     int mContentChangeTypes;
     int mWindowChangeTypes;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index c59c491..e88682e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -139,6 +139,8 @@
 
     int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
 
+    int mMinimumUiTimeout;
+
     boolean mIsTouchExplorationEnabled;
 
     @UnsupportedAppUsage
@@ -320,6 +322,11 @@
         public void setRelevantEventTypes(int eventTypes) {
             mRelevantEventTypes = eventTypes;
         }
+
+        @Override
+        public void setMinimumUiTimeout(int uiTimeout) {
+            mMinimumUiTimeout = uiTimeout;
+        }
     };
 
     /**
@@ -827,6 +834,19 @@
     }
 
     /**
+     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+     * on the screen for at least this long to give users time to react. Some users may need
+     * extra time to review the controls, or to reach them, or to activate assistive technology
+     * to activate the controls automatically.
+     *
+     * @return The minimum ui timeout for the current user in milliseconds.
+     * {@link Integer#MAX_VALUE} if timeout is infinite.
+     */
+    public int getMinimumUiTimeoutMillis() {
+        return mMinimumUiTimeout;
+    }
+
+    /**
      * Get the preparers that are registered for an accessibility ID
      *
      * @param id The ID of interest
@@ -1139,6 +1159,7 @@
             final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
             setStateLocked(IntPair.first(userStateAndRelevantEvents));
             mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
+            mMinimumUiTimeout = service.getMinimumUiTimeout();
             mService = service;
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c93e2c1..3e2ef18 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -72,4 +72,6 @@
 
     // System process only
     boolean sendFingerprintGesture(int gestureKeyCode);
+
+    int getMinimumUiTimeout();
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 9cc0315..d2ddca3 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -29,4 +29,6 @@
     void notifyServicesStateChanged();
 
     void setRelevantEventTypes(int eventTypes);
+
+    void setMinimumUiTimeout(int uiTimeout);
 }
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index f45507c..e1600c4 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -89,14 +89,17 @@
      *
      * @param token special token for the system to identify
      *              {@link InputMethodService}
+     * @param displayId The id of the display that current IME shown.
+     *                  Used for {{@link #updateInputMethodDisplay(int)}}
      * @param privilegedOperations IPC endpoint to do some privileged
      *                             operations that are allowed only to the
      *                             current IME.
      * @hide
      */
     @MainThread
-    default void initializeInternal(IBinder token,
+    default void initializeInternal(IBinder token, int displayId,
             IInputMethodPrivilegedOperations privilegedOperations) {
+        updateInputMethodDisplay(displayId);
         attachToken(token);
     }
 
@@ -115,6 +118,15 @@
     public void attachToken(IBinder token);
 
     /**
+     * Update context display according to given displayId.
+     *
+     * @param displayId The id of the display that need to update for context.
+     * @hide
+     */
+    @MainThread
+    public void updateInputMethodDisplay(int displayId);
+
+    /**
      * Bind a new application environment in to the input method, so that it
      * can later start and stop input processing.
      * Typically this method is called when this input method is enabled in an
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index c51c5e2..508509a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -336,7 +336,7 @@
     /**
      * The InputConnection that was last retrieved from the served view.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     ControlledInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 61a6972..14c879e 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -28,7 +28,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -384,7 +384,7 @@
             if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
                 mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag);
             } else {
-                mCachedLocaleObj = LocaleUtils.constructLocaleFromString(mSubtypeLocale);
+                mCachedLocaleObj = SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale);
             }
             return mCachedLocaleObj;
         }
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index 41b70b6..d904d467 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -25,7 +25,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -228,7 +228,7 @@
         if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
             return Locale.forLanguageTag(mSubtypeLanguageTag);
         }
-        return LocaleUtils.constructLocaleFromString(mSubtypeLocale);
+        return SubtypeLocaleUtils.constructLocaleFromString(mSubtypeLocale);
     }
 
     /**
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 1d3a617..7839a00 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -36,14 +36,14 @@
     public abstract void showInterstitial(boolean allowReporting);
 
     /**
-     * Act as if the user clicked "visit this unsafe site."
+     * Act as if the user clicked the "visit this unsafe site" button.
      *
      * @param report {@code true} to enable Safe Browsing reporting.
      */
     public abstract void proceed(boolean report);
 
     /**
-     * Act as if the user clicked "back to safety."
+     * Act as if the user clicked the "back to safety" button.
      *
      * @param report {@code true} to enable Safe Browsing reporting.
      */
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index e9a9e8f..46b1f6e 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -51,9 +51,6 @@
 
     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
 
-    public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
-            "persist.sys.webview.vmsize";
-
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index cabba06..5a6aeba 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -17,15 +17,14 @@
 package android.webkit;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
-import android.content.pm.ApplicationInfo;
+import android.app.ActivityThread;
+import android.app.LoadedApk;
+import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -33,11 +32,7 @@
 
 import dalvik.system.VMRuntime;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.Arrays;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
 /**
  * @hide
@@ -50,7 +45,6 @@
             "/data/misc/shared_relro/libwebviewchromium32.relro";
     private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
             "/data/misc/shared_relro/libwebviewchromium64.relro";
-    private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
 
     private static final boolean DEBUG = false;
 
@@ -69,18 +63,26 @@
             boolean result = false;
             boolean is64Bit = VMRuntime.getRuntime().is64Bit();
             try {
-                if (args.length != 1 || args[0] == null) {
+                if (args.length != 2 || args[0] == null || args[1] == null) {
                     Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
                     return;
                 }
-                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]);
+                String packageName = args[0];
+                String libraryFileName = args[1];
+                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), package: "
+                        + packageName + " library: " + libraryFileName);
                 if (!sAddressSpaceReserved) {
                     Log.e(LOGTAG, "can't create relro file; address space not reserved");
                     return;
                 }
-                result = nativeCreateRelroFile(args[0] /* path */,
+                LoadedApk apk = ActivityThread.currentActivityThread().getPackageInfo(
+                        packageName,
+                        null,
+                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                result = nativeCreateRelroFile(libraryFileName,
                                                is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :
-                                                         CHROMIUM_WEBVIEW_NATIVE_RELRO_32);
+                                                         CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                               apk.getClassLoader());
                 if (result && DEBUG) Log.v(LOGTAG, "created relro file");
             } finally {
                 // We must do our best to always notify the update service, even if something fails.
@@ -101,7 +103,8 @@
     /**
      * Create a single relro file by invoking an isolated process that to do the actual work.
      */
-    static void createRelroFile(final boolean is64Bit, @NonNull WebViewNativeLibrary nativeLib) {
+    static void createRelroFile(final boolean is64Bit, @NonNull String packageName,
+            @NonNull String libraryFileName) {
         final String abi =
                 is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
 
@@ -119,13 +122,10 @@
         };
 
         try {
-            if (nativeLib == null || nativeLib.path == null) {
-                throw new IllegalArgumentException(
-                        "Native library paths to the WebView RelRo process must not be null!");
-            }
             boolean success = LocalServices.getService(ActivityManagerInternal.class)
                     .startIsolatedProcess(
-                            RelroFileCreator.class.getName(), new String[] { nativeLib.path },
+                            RelroFileCreator.class.getName(),
+                            new String[] { packageName, libraryFileName },
                             "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler);
             if (!success) throw new Exception("Failed to start the relro file creator process");
         } catch (Throwable t) {
@@ -140,83 +140,50 @@
      * be called whenever we change WebView provider.
      * @return the number of relro processes started.
      */
-    static int prepareNativeLibraries(PackageInfo webviewPackageInfo)
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewNativeLibrary nativeLib32bit =
-                getWebViewNativeLibrary(webviewPackageInfo, false /* is64bit */);
-        WebViewNativeLibrary nativeLib64bit =
-                getWebViewNativeLibrary(webviewPackageInfo, true /* is64bit */);
-        updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit);
-
-        return createRelros(nativeLib32bit, nativeLib64bit);
+    static int prepareNativeLibraries(@NonNull PackageInfo webViewPackageInfo) {
+        // TODO(torne): new way of calculating VM size
+        // updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit);
+        String libraryFileName = WebViewFactory.getWebViewLibrary(
+                webViewPackageInfo.applicationInfo);
+        if (libraryFileName == null) {
+            // Can't do anything with no filename, don't spawn any processes.
+            return 0;
+        }
+        return createRelros(webViewPackageInfo.packageName, libraryFileName);
     }
 
     /**
      * @return the number of relro processes started.
      */
-    private static int createRelros(@Nullable WebViewNativeLibrary nativeLib32bit,
-            @Nullable WebViewNativeLibrary nativeLib64bit) {
+    private static int createRelros(@NonNull String packageName, @NonNull String libraryFileName) {
         if (DEBUG) Log.v(LOGTAG, "creating relro files");
         int numRelros = 0;
 
         if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-            if (nativeLib32bit == null) {
-                Log.e(LOGTAG, "No 32-bit WebView library path, skipping relro creation.");
-            } else {
-                if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
-                createRelroFile(false /* is64Bit */, nativeLib32bit);
-                numRelros++;
-            }
+            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
+            createRelroFile(false /* is64Bit */, packageName, libraryFileName);
+            numRelros++;
         }
 
         if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-            if (nativeLib64bit == null) {
-                Log.e(LOGTAG, "No 64-bit WebView library path, skipping relro creation.");
-            } else {
-                if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
-                createRelroFile(true /* is64Bit */, nativeLib64bit);
-                numRelros++;
-            }
+            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
+            createRelroFile(true /* is64Bit */, packageName, libraryFileName);
+            numRelros++;
         }
         return numRelros;
     }
 
     /**
-     *
-     * @return the native WebView libraries in the new WebView APK.
-     */
-    private static void updateWebViewZygoteVmSize(
-            @Nullable WebViewNativeLibrary nativeLib32bit,
-            @Nullable WebViewNativeLibrary nativeLib64bit)
-            throws WebViewFactory.MissingWebViewPackageException {
-        // Find the native libraries of the new WebView package, to change the size of the
-        // memory region in the Zygote reserved for the library.
-        long newVmSize = 0L;
-
-        if (nativeLib32bit != null) newVmSize = Math.max(newVmSize, nativeLib32bit.size);
-        if (nativeLib64bit != null) newVmSize = Math.max(newVmSize, nativeLib64bit.size);
-
-        if (DEBUG) {
-            Log.v(LOGTAG, "Based on library size, need " + newVmSize
-                    + " bytes of address space.");
-        }
-        // The required memory can be larger than the file on disk (due to .bss), and an
-        // upgraded version of the library will likely be larger, so always attempt to
-        // reserve twice as much as we think to allow for the library to grow during this
-        // boot cycle.
-        newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
-        Log.d(LOGTAG, "Setting new address space to " + newVmSize);
-        setWebViewZygoteVmSize(newVmSize);
-    }
-
-    /**
      * Reserve space for the native library to be loaded into.
      */
     static void reserveAddressSpaceInZygote() {
         System.loadLibrary("webviewchromium_loader");
-        long addressSpaceToReserve =
-                SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
-                CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+        boolean is64Bit = VMRuntime.getRuntime().is64Bit();
+        // On 64-bit address space is really cheap and we can reserve 1GB which is plenty.
+        // On 32-bit it's fairly scarce and we should keep it to a realistic number that
+        // permits some future growth but doesn't hog space: we use 100MB which is more than 2x
+        // the current requirement.
+        long addressSpaceToReserve = is64Bit ? 1 * 1024 * 1024 * 1024 : 100 * 1024 * 1024;
         sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
 
         if (sAddressSpaceReserved) {
@@ -253,106 +220,7 @@
         return result;
     }
 
-    /**
-     * Fetch WebView's native library paths from {@param packageInfo}.
-     * @hide
-     */
-    @Nullable
-    @VisibleForTesting
-    public static WebViewNativeLibrary getWebViewNativeLibrary(PackageInfo packageInfo,
-            boolean is64bit) throws WebViewFactory.MissingWebViewPackageException {
-        ApplicationInfo ai = packageInfo.applicationInfo;
-        final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai);
-
-        String dir = getWebViewNativeLibraryDirectory(ai, is64bit /* 64bit */);
-
-        WebViewNativeLibrary lib = findNativeLibrary(ai, nativeLibFileName,
-                is64bit ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS, dir);
-
-        if (DEBUG) {
-            Log.v(LOGTAG, String.format("Native %d-bit lib: %s", is64bit ? 64 : 32, lib.path));
-        }
-        return lib;
-    }
-
-    /**
-     * @return the directory of the native WebView library with bitness {@param is64bit}.
-     * @hide
-     */
-    @VisibleForTesting
-    public static String getWebViewNativeLibraryDirectory(ApplicationInfo ai, boolean is64bit) {
-        // Primary arch has the same bitness as the library we are looking for.
-        if (is64bit == VMRuntime.is64BitAbi(ai.primaryCpuAbi)) return ai.nativeLibraryDir;
-
-        // Secondary arch has the same bitness as the library we are looking for.
-        if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
-            return ai.secondaryNativeLibraryDir;
-        }
-
-        return "";
-    }
-
-    /**
-     * @return an object describing a native WebView library given the directory path of that
-     * library, or null if the library couldn't be found.
-     */
-    @Nullable
-    private static WebViewNativeLibrary findNativeLibrary(ApplicationInfo ai,
-            String nativeLibFileName, String[] abiList, String libDirectory)
-            throws WebViewFactory.MissingWebViewPackageException {
-        if (TextUtils.isEmpty(libDirectory)) return null;
-        String libPath = libDirectory + "/" + nativeLibFileName;
-        File f = new File(libPath);
-        if (f.exists()) {
-            return new WebViewNativeLibrary(libPath, f.length());
-        } else {
-            return getLoadFromApkPath(ai.sourceDir, abiList, nativeLibFileName);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @VisibleForTesting
-    public static class WebViewNativeLibrary {
-        public final String path;
-        public final long size;
-
-        WebViewNativeLibrary(String path, long size) {
-            this.path = path;
-            this.size = size;
-        }
-    }
-
-    private static WebViewNativeLibrary getLoadFromApkPath(String apkPath,
-                                                           String[] abiList,
-                                                           String nativeLibFileName)
-            throws WebViewFactory.MissingWebViewPackageException {
-        // Search the APK for a native library conforming to a listed ABI.
-        try (ZipFile z = new ZipFile(apkPath)) {
-            for (String abi : abiList) {
-                final String entry = "lib/" + abi + "/" + nativeLibFileName;
-                ZipEntry e = z.getEntry(entry);
-                if (e != null && e.getMethod() == ZipEntry.STORED) {
-                    // Return a path formatted for dlopen() load from APK.
-                    return new WebViewNativeLibrary(apkPath + "!/" + entry, e.getSize());
-                }
-            }
-        } catch (IOException e) {
-            throw new WebViewFactory.MissingWebViewPackageException(e);
-        }
-        return null;
-    }
-
-    /**
-     * Sets the size of the memory area in which to store the relro section.
-     */
-    private static void setWebViewZygoteVmSize(long vmSize) {
-        SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
-                Long.toString(vmSize));
-    }
-
     static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
-    static native boolean nativeCreateRelroFile(String lib, String relro);
+    static native boolean nativeCreateRelroFile(String lib, String relro, ClassLoader clazzLoader);
     static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader);
 }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index dd6c923..f3fe16e 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -682,7 +682,7 @@
 
     /**
      * Sets the currently selected item. To support accessibility subclasses that
-     * override this method must invoke the overriden super method first.
+     * override this method must invoke the overridden super method first.
      *
      * @param position Index (starting at 0) of the data item to be selected.
      */
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 71d13a9..cbd624e 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -24,6 +24,7 @@
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.TextUtils;
@@ -533,7 +534,7 @@
      *
      * @hide Pending API council approval
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setDropDownAnimationStyle(int animationStyle) {
         mPopup.setAnimationStyle(animationStyle);
     }
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 452e903..f2e478d 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -653,7 +653,7 @@
     }
 
     /**
-     * <p>Returns the view at the specified index. This method can be overriden
+     * <p>Returns the view at the specified index. This method can be overridden
      * to take into account virtual children. Refer to
      * {@link android.widget.TableLayout} and {@link android.widget.TableRow}
      * for an example.</p>
@@ -1527,7 +1527,7 @@
 
     /**
      * <p>Measure the child according to the parent's measure specs. This
-     * method should be overriden by subclasses to force the sizing of
+     * method should be overridden by subclasses to force the sizing of
      * children. This method is called by {@link #measureVertical(int, int)} and
      * {@link #measureHorizontal(int, int)}.</p>
      *
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 5b5950d..10e1dfb 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -36,6 +36,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -1292,7 +1293,7 @@
         mSearchSrcTextView.dismissDropDown();
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private void onCloseClicked() {
         CharSequence text = mSearchSrcTextView.getText();
         if (TextUtils.isEmpty(text)) {
@@ -1590,7 +1591,7 @@
     /**
      * Sets the text in the query box, without updating the suggestions.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private void setQuery(CharSequence query) {
         mSearchSrcTextView.setText(query, true);
         // Move the cursor to the end
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d913273..a86e6f8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3609,7 +3609,7 @@
     /**
      * Read the Text Appearance attributes from a given TypedArray and set its values to the given
      * set. If the TypedArray contains a value that was already set in the given attributes, that
-     * will be overriden.
+     * will be overridden.
      *
      * @param context The Context to be used
      * @param appearance The TypedArray to read properties from
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 3fbc819..10cf702 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -27,6 +27,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -443,7 +444,7 @@
          * schedule handleShow into the right thread
          */
         @Override
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
             mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 1bbd7e8..adb7f2f 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.Layout;
@@ -137,7 +138,7 @@
     @UnsupportedAppUsage
     private TextView mTitleTextView;
     private TextView mSubtitleTextView;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 14881eb..8b45d99 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -38,6 +38,7 @@
 import android.media.TtmlRenderer;
 import android.media.WebVttRenderer;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -85,7 +86,7 @@
 
     // all possible internal states
     private static final int STATE_ERROR = -1;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final int STATE_IDLE = 0;
     private static final int STATE_PREPARING = 1;
     private static final int STATE_PREPARED = 2;
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 90712fd..e83e79b 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.accessibility;
 
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+
+import static com.android.internal.util.ArrayUtils.convertToLongArray;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -34,23 +38,23 @@
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.Voice;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-
 import android.widget.Toast;
+
 import com.android.internal.R;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.util.Collections;
+import java.util.Locale;
 import java.util.Map;
 
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-
-import static com.android.internal.util.ArrayUtils.convertToLongArray;
-
 /**
  * Class to help manage the accessibility shortcut
  */
@@ -70,6 +74,7 @@
     private static Map<ComponentName, ToggleableFrameworkFeatureInfo> sFrameworkShortcutFeaturesMap;
 
     private final Context mContext;
+    private final Handler mHandler;
     private AlertDialog mAlertDialog;
     private boolean mIsShortcutEnabled;
     private boolean mEnabledOnLockScreen;
@@ -123,6 +128,7 @@
 
     public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
         mContext = context;
+        mHandler = handler;
         mUserId = initialUserId;
 
         // Keep track of state of shortcut settings
@@ -189,22 +195,6 @@
         final int userId = ActivityManager.getCurrentUser();
         final int dialogAlreadyShown = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
-        // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
-        // have less ways of providing feedback like vibration.
-        final int audioAttributesUsage = hasFeatureLeanback()
-                ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
-                : AudioAttributes.USAGE_NOTIFICATION_EVENT;
-
-        // Play a notification tone
-        final Ringtone tone =
-                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
-        if (tone != null) {
-            tone.setAudioAttributes(new AudioAttributes.Builder()
-                .setUsage(audioAttributesUsage)
-                .build());
-            tone.play();
-        }
-
         // Play a notification vibration
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         if ((vibrator != null) && vibrator.hasVibrator()) {
@@ -223,6 +213,9 @@
             if (mAlertDialog == null) {
                 return;
             }
+            if (!performTtsPrompt(mAlertDialog)) {
+                playNotificationTone();
+            }
             Window w = mAlertDialog.getWindow();
             WindowManager.LayoutParams attr = w.getAttributes();
             attr.type = TYPE_KEYGUARD_DIALOG;
@@ -231,6 +224,7 @@
             Settings.Secure.putIntForUser(
                     cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
         } else {
+            playNotificationTone();
             if (mAlertDialog != null) {
                 mAlertDialog.dismiss();
                 mAlertDialog = null;
@@ -344,6 +338,102 @@
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
+    private void playNotificationTone() {
+        // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
+        // have less ways of providing feedback like vibration.
+        final int audioAttributesUsage = hasFeatureLeanback()
+                ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
+                : AudioAttributes.USAGE_NOTIFICATION_EVENT;
+
+        // Play a notification tone
+        final Ringtone tone = mFrameworkObjectProvider.getRingtone(mContext,
+                Settings.System.DEFAULT_NOTIFICATION_URI);
+        if (tone != null) {
+            tone.setAudioAttributes(new AudioAttributes.Builder()
+                    .setUsage(audioAttributesUsage)
+                    .build());
+            tone.play();
+        }
+    }
+
+    private boolean performTtsPrompt(AlertDialog alertDialog) {
+        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+        if (serviceInfo == null) {
+            return false;
+        }
+        if ((serviceInfo.flags & AccessibilityServiceInfo
+                .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK) == 0) {
+            return false;
+        }
+        final TtsPrompt tts = new TtsPrompt();
+        alertDialog.setOnDismissListener(dialog -> tts.dismiss());
+        return true;
+    }
+
+    /**
+     * Class to wrap TextToSpeech for shortcut dialog spoken feedback.
+     */
+    private class TtsPrompt implements TextToSpeech.OnInitListener {
+        private final CharSequence mText;
+        private boolean mDismiss;
+        private TextToSpeech mTts;
+
+        TtsPrompt() {
+            mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback);
+            mTts = mFrameworkObjectProvider.getTextToSpeech(mContext, this);
+        }
+
+        /**
+         * Releases the resources used by the TextToSpeech, when dialog dismiss.
+         */
+        public void dismiss() {
+            mDismiss = true;
+            mHandler.sendMessage(PooledLambda.obtainMessage(TextToSpeech::shutdown, mTts));
+        }
+
+        @Override
+        public void onInit(int status) {
+            if (status != TextToSpeech.SUCCESS) {
+                Slog.d(TAG, "Tts init fail, status=" + Integer.toString(status));
+                playNotificationTone();
+                return;
+            }
+            mHandler.sendMessage(PooledLambda.obtainMessage(TtsPrompt::play, this));
+        }
+
+        private void play() {
+            if (mDismiss) {
+                return;
+            }
+            int status = TextToSpeech.ERROR;
+            if (setLanguage(Locale.getDefault())) {
+                status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
+            }
+            if (status != TextToSpeech.SUCCESS) {
+                Slog.d(TAG, "Tts play fail");
+                playNotificationTone();
+            }
+        }
+
+        /**
+         * @return false if tts language is not available
+         */
+        private boolean setLanguage(final Locale locale) {
+            int status = mTts.isLanguageAvailable(locale);
+            if (status == TextToSpeech.LANG_MISSING_DATA
+                    || status == TextToSpeech.LANG_NOT_SUPPORTED) {
+                return false;
+            }
+            mTts.setLanguage(locale);
+            Voice voice = mTts.getVoice();
+            if (voice == null || (voice.getFeatures() != null && voice.getFeatures()
+                    .contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))) {
+                return false;
+            }
+            return true;
+        }
+    }
+
     /**
      * Immutable class to hold info about framework features that can be controlled by shortcut
      */
@@ -406,5 +496,23 @@
         public Context getSystemUiContext() {
             return ActivityThread.currentActivityThread().getSystemUiContext();
         }
+
+        /**
+         * @param ctx A context for TextToSpeech
+         * @param listener TextToSpeech initialization callback
+         * @return TextToSpeech instance
+         */
+        public TextToSpeech getTextToSpeech(Context ctx, TextToSpeech.OnInitListener listener) {
+            return new TextToSpeech(ctx, listener);
+        }
+
+        /**
+         * @param ctx context for ringtone
+         * @param uri ringtone uri
+         * @return Ringtone instance
+         */
+        public Ringtone getRingtone(Context ctx, Uri uri) {
+            return RingtoneManager.getRingtone(ctx, uri);
+        }
     }
 }
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index 7b25a06..3fd88db 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,10 +51,8 @@
 
     private static final boolean DEBUG = true;
 
-    public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
     public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
-    public static final int THRESHOLD_COLOR_DARK = 0xff212121;
-    public static final int MAIN_COLOR_DARK = 0xff000000;
+    public static final int MAIN_COLOR_DARK = 0xff212121;
 
     private final TonalPalette mGreyPalette;
     private final ArrayList<TonalPalette> mTonalPalettes;
@@ -197,12 +195,12 @@
         // light fallback or darker than our dark fallback.
         ColorUtils.colorToHSL(mainColor, mTmpHSL);
         final float mainLuminosity = mTmpHSL[2];
-        ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
+        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
         final float lightLuminosity = mTmpHSL[2];
         if (mainLuminosity > lightLuminosity) {
             return false;
         }
-        ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
+        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
         final float darkLuminosity = mTmpHSL[2];
         if (mainLuminosity < darkLuminosity) {
             return false;
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
deleted file mode 100644
index f7360eb..0000000
--- a/core/java/com/android/internal/inputmethod/LocaleUtils.java
+++ /dev/null
@@ -1,358 +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.internal.inputmethod;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.icu.util.ULocale;
-import android.os.LocaleList;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-
-public final class LocaleUtils {
-
-    @VisibleForTesting
-    public interface LocaleExtractor<T> {
-        @Nullable
-        Locale get(@Nullable T source);
-    }
-
-    /**
-     * Calculates a matching score for the single desired locale.
-     *
-     * @see LocaleUtils#filterByLanguage(List, LocaleExtractor, LocaleList, ArrayList)
-     *
-     * @param supported The locale supported by IME subtype.
-     * @param desired The locale preferred by user.
-     * @return A score based on the locale matching for the default subtype enabling.
-     */
-    @IntRange(from=1, to=3)
-    private static byte calculateMatchingSubScore(@NonNull final ULocale supported,
-            @NonNull final ULocale desired) {
-        // Assuming supported/desired is fully expanded.
-        if (supported.equals(desired)) {
-            return 3;  // Exact match.
-        }
-
-        // Skip language matching since it was already done in calculateMatchingScore.
-
-        final String supportedScript = supported.getScript();
-        if (supportedScript.isEmpty() || !supportedScript.equals(desired.getScript())) {
-            // TODO: Need subscript matching. For example, Hanb should match with Bopo.
-            return 1;
-        }
-
-        final String supportedCountry = supported.getCountry();
-        if (supportedCountry.isEmpty() || !supportedCountry.equals(desired.getCountry())) {
-            return 2;
-        }
-
-        // Ignore others e.g. variants, extensions.
-        return 3;
-    }
-
-    private static final class ScoreEntry implements Comparable<ScoreEntry> {
-        public int mIndex = -1;
-        @NonNull public final byte[] mScore;  // matching score of the i-th system languages.
-
-        ScoreEntry(@NonNull byte[] score, int index) {
-            mScore = new byte[score.length];
-            set(score, index);
-        }
-
-        private void set(@NonNull byte[] score, int index) {
-            for (int i = 0; i < mScore.length; ++i) {
-                mScore[i] = score[i];
-            }
-            mIndex = index;
-        }
-
-        /**
-         * Update score and index if the given score is better than this.
-         */
-        public void updateIfBetter(@NonNull byte[] score, int index) {
-            if (compare(mScore, score) == -1) {  // mScore < score
-                set(score, index);
-            }
-        }
-
-        /**
-         * Provides comaprison for bytes[].
-         *
-         * <p> Comparison does as follows. If the first value of {@code left} is larger than the
-         * first value of {@code right}, {@code left} is large than {@code right}.  If the first
-         * value of {@code left} is less than the first value of {@code right}, {@code left} is less
-         * than {@code right}. If the first value of {@code left} and the first value of
-         * {@code right} is equal, do the same comparison to the next value. Finally if all values
-         * in {@code left} and {@code right} are equal, {@code left} and {@code right} is equal.</p>
-         *
-         * @param left The length must be equal to {@code right}.
-         * @param right The length must be equal to {@code left}.
-         * @return 1 if {@code left} is larger than {@code right}. -1 if {@code left} is less than
-         * {@code right}. 0 if {@code left} and {@code right} is equal.
-         */
-        @IntRange(from=-1, to=1)
-        private static int compare(@NonNull byte[] left, @NonNull byte[] right) {
-            for (int i = 0; i < left.length; ++i) {
-                if (left[i] > right[i]) {
-                    return 1;
-                } else if (left[i] < right[i]) {
-                    return -1;
-                }
-            }
-            return 0;
-        }
-
-        @Override
-        public int compareTo(final ScoreEntry other) {
-            return -1 * compare(mScore, other.mScore);  // Order by descending order.
-        }
-    }
-
-    /**
-     * Filters the given items based on language preferences.
-     *
-     * <p>For each language found in {@code preferredLocales}, this method tries to copy at most
-     * one best-match item from {@code source} to {@code dest}.  For example, if
-     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLocales},
-     * this method tries to copy at most one English locale, at most one Japanese, and at most one
-     * French locale from {@code source} to {@code dest}.  Here the best matching English locale
-     * will be searched from {@code source} based on matching score. For the score design, see
-     * {@link LocaleUtils#calculateMatchingSubScore(ULocale, ULocale)}</p>
-     *
-     * @param sources Source items to be filtered.
-     * @param extractor Type converter from the source items to {@link Locale} object.
-     * @param preferredLocales Ordered list of locales with which the input items will be
-     * filtered.
-     * @param dest Destination into which the filtered items will be added.
-     * @param <T> Type of the data items.
-     */
-    @VisibleForTesting
-    public static <T> void filterByLanguage(
-            @NonNull List<T> sources,
-            @NonNull LocaleExtractor<T> extractor,
-            @NonNull LocaleList preferredLocales,
-            @NonNull ArrayList<T> dest) {
-        if (preferredLocales.isEmpty()) {
-            return;
-        }
-
-        final int numPreferredLocales = preferredLocales.size();
-        final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
-        final byte[] score = new byte[numPreferredLocales];
-        final ULocale[] preferredULocaleCache = new ULocale[numPreferredLocales];
-
-        final int sourceSize = sources.size();
-        for (int i = 0; i < sourceSize; ++i) {
-            final Locale locale = extractor.get(sources.get(i));
-            if (locale == null) {
-                continue;
-            }
-
-            boolean canSkip = true;
-            for (int j = 0; j < numPreferredLocales; ++j) {
-                final Locale preferredLocale = preferredLocales.get(j);
-                if (!TextUtils.equals(locale.getLanguage(), preferredLocale.getLanguage())) {
-                    score[j] = 0;
-                    continue;
-                }
-                if (preferredULocaleCache[j] == null) {
-                    preferredULocaleCache[j] = ULocale.addLikelySubtags(
-                            ULocale.forLocale(preferredLocale));
-                }
-                score[j] = calculateMatchingSubScore(
-                        preferredULocaleCache[j],
-                        ULocale.addLikelySubtags(ULocale.forLocale(locale)));
-                if (canSkip && score[j] != 0) {
-                    canSkip = false;
-                }
-            }
-            if (canSkip) {
-                continue;
-            }
-
-            final String lang = locale.getLanguage();
-            final ScoreEntry bestScore = scoreboard.get(lang);
-            if (bestScore == null) {
-                scoreboard.put(lang, new ScoreEntry(score, i));
-            } else {
-                bestScore.updateIfBetter(score, i);
-            }
-        }
-
-        final ScoreEntry[] result = scoreboard.values().toArray(new ScoreEntry[scoreboard.size()]);
-        Arrays.sort(result);
-        for (final ScoreEntry entry : result) {
-            dest.add(sources.get(entry.mIndex));
-        }
-    }
-
-    public static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr)) {
-            return null;
-        }
-        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
-        String[] localeParams = localeStr.split("_", 3);
-        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
-            // Convert a locale whose language is "tl" to one whose language is "fil".
-            // For example, "tl_PH" will get converted to "fil_PH".
-            // Versions of Android earlier than Lollipop did not support three letter language
-            // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
-            // On Lollipop and above, the current three letter version must be used.
-            localeParams[0] = "fil";
-        }
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
-    /**
-     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
-     * checker service.
-     *
-     * <p>If the system language is English, and the region is also explicitly specified in the
-     * system locale, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * <p>If the system language is English, but no region is specified in the system locale,
-     * the following fallback order will be applied.</p>
-     * <ul>
-     * <li>("en")</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * </ul>
-     *
-     * <p>If the system language is not English, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region) (if exists)</li>
-     * <li>(system-locale-language) (if exists)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * @param systemLocale the current system locale to be taken into consideration.
-     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
-     */
-    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
-            @Nullable final Locale systemLocale) {
-        final Locale systemLocaleLanguageCountryVariant;
-        final Locale systemLocaleLanguageCountry;
-        final Locale systemLocaleLanguage;
-        if (systemLocale != null) {
-            final String language = systemLocale.getLanguage();
-            final boolean hasLanguage = !TextUtils.isEmpty(language);
-            final String country = systemLocale.getCountry();
-            final boolean hasCountry = !TextUtils.isEmpty(country);
-            final String variant = systemLocale.getVariant();
-            final boolean hasVariant = !TextUtils.isEmpty(variant);
-            if (hasLanguage && hasCountry && hasVariant) {
-                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
-            } else {
-                systemLocaleLanguageCountryVariant = null;
-            }
-            if (hasLanguage && hasCountry) {
-                systemLocaleLanguageCountry = new Locale(language, country);
-            } else {
-                systemLocaleLanguageCountry = null;
-            }
-            if (hasLanguage) {
-                systemLocaleLanguage = new Locale(language);
-            } else {
-                systemLocaleLanguage = null;
-            }
-        } else {
-            systemLocaleLanguageCountryVariant = null;
-            systemLocaleLanguageCountry = null;
-            systemLocaleLanguage = null;
-        }
-
-        final ArrayList<Locale> locales = new ArrayList<>();
-        if (systemLocaleLanguageCountryVariant != null) {
-            locales.add(systemLocaleLanguageCountryVariant);
-        }
-
-        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
-            if (systemLocaleLanguageCountry != null) {
-                // If the system language is English, and the region is also explicitly specified,
-                // following fallback order will be applied.
-                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
-                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
-                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
-                // - en
-                if (systemLocaleLanguageCountry != null) {
-                    locales.add(systemLocaleLanguageCountry);
-                }
-                if (!Locale.US.equals(systemLocaleLanguageCountry)) {
-                    locales.add(Locale.US);
-                }
-                if (!Locale.UK.equals(systemLocaleLanguageCountry)) {
-                    locales.add(Locale.UK);
-                }
-                locales.add(Locale.ENGLISH);
-            } else {
-                // If the system language is English, but no region is specified, following
-                // fallback order will be applied.
-                // - en
-                // - en_US
-                // - en_GB
-                locales.add(Locale.ENGLISH);
-                locales.add(Locale.US);
-                locales.add(Locale.UK);
-            }
-        } else {
-            // If the system language is not English, the fallback order will be
-            // - systemLocaleLanguageCountry  [if non-null]
-            // - systemLocaleLanguage  [if non-null]
-            // - en_US
-            // - en_GB
-            // - en
-            if (systemLocaleLanguageCountry != null) {
-                locales.add(systemLocaleLanguageCountry);
-            }
-            if (systemLocaleLanguage != null) {
-                locales.add(systemLocaleLanguage);
-            }
-            locales.add(Locale.US);
-            locales.add(Locale.UK);
-            locales.add(Locale.ENGLISH);
-        }
-        return locales;
-    }
-}
diff --git a/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java
new file mode 100644
index 0000000..9ea4fa2
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/SubtypeLocaleUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.internal.inputmethod;
+
+import android.annotation.Nullable;
+import android.text.TextUtils;
+
+import java.util.Locale;
+
+/**
+ * A utility class to handle {@link Locale} related logic for
+ * {@link android.view.inputmethod.InputMethodSubtype} and
+ * {@link android.view.textservice.SpellCheckerSubtype}.
+ */
+public class SubtypeLocaleUtils {
+    /**
+     * Maintains deprecated logic about how subtype locales specified in XML resources have been
+     * parsed.
+     *
+     * <p>This logic is kept basically for compatibility purpose.  Consider relying on languageTag
+     * attribute instead.</p>
+     *
+     * @param localeStr string representation that is specified in the locale attribute
+     * @return {@link Locale} object parsed from {@code localeStr}. {@code null} for unexpected
+     *         format
+     *
+     * @attr ref android.R.styleable#InputMethod_Subtype_imeSubtypeLocale
+     * @attr ref android.R.styleable#InputMethod_Subtype_languageTag
+     * @attr ref android.R.styleable#SpellChecker_Subtype_languageTag
+     * @attr ref android.R.styleable#SpellChecker_Subtype_subtypeLocale
+     */
+    @Nullable
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
+            // Convert a locale whose language is "tl" to one whose language is "fil".
+            // For example, "tl_PH" will get converted to "fil_PH".
+            // Versions of Android earlier than Lollipop did not support three letter language
+            // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
+            // On Lollipop and above, the current three letter version must be used.
+            localeParams[0] = "fil";
+        }
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 02a8b22..0650d0af 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -106,6 +106,7 @@
         synchronized (entry) {
             entry.exceptionCount++;
         }
+
         recycleSession(session);
     }
 
@@ -116,29 +117,29 @@
 
     /** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */
     public List<ExportedEntry> getEntries() {
-        final ArrayList<ExportedEntry> entries;
+        final ArrayList<ExportedEntry> exportedEntries;
         synchronized (mLock) {
             final int size = mEntries.size();
-            entries = new ArrayList<>(size);
+            exportedEntries = new ArrayList<>(size);
             for (int i = 0; i < size; i++) {
                 Entry entry = mEntries.valueAt(i);
                 synchronized (entry) {
-                    entries.add(new ExportedEntry(entry));
+                    exportedEntries.add(new ExportedEntry(entry));
                 }
             }
         }
         // Add the overflow and collision entries only if they have any data.
-        if (mOverflowEntry.messageCount > 0 || mOverflowEntry.exceptionCount > 0) {
-            synchronized (mOverflowEntry) {
-                entries.add(new ExportedEntry(mOverflowEntry));
+        maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
+        maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
+        return exportedEntries;
+    }
+
+    private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) {
+        synchronized (specialEntry) {
+            if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) {
+                exportedEntries.add(new ExportedEntry(specialEntry));
             }
         }
-        if (mHashCollisionEntry.messageCount > 0 || mHashCollisionEntry.exceptionCount > 0) {
-            synchronized (mHashCollisionEntry) {
-                entries.add(new ExportedEntry(mHashCollisionEntry));
-            }
-        }
-        return entries;
     }
 
     /** Removes all collected data. */
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 16ca4fc..1038199 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -455,7 +455,7 @@
      * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
      */
     public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
-        if (color == Notification.COLOR_DEFAULT) {
+        if (color == Notification.COLOR_DEFAULT || defaultBackgroundIsDark) {
             int res = defaultBackgroundIsDark
                     ? com.android.internal.R.color.notification_default_color_dark
                     : com.android.internal.R.color.notification_default_color_light;
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 21d750c..e65d114 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,24 +1,4 @@
-per-file AsyncChannel*=lorenzo@google.com
-per-file AsyncChannel*=satk@google.com
-per-file AsyncChannel*=silberst@google.com
-per-file BitUtils*=ek@google.com
-per-file BitUtils*=lorenzo@google.com
-per-file BitUtils*=satk@google.com
-per-file MessageUtils*=ek@google.com
-per-file MessageUtils*=lorenzo@google.com
-per-file MessageUtils*=satk@google.com
-per-file Protocol*=ek@google.com
-per-file Protocol*=lorenzo@google.com
-per-file Protocol*=quiche@google.com
-per-file Protocol*=satk@google.com
-per-file Protocol*=silberst@google.com
-per-file RingBuffer*=ek@google.com
-per-file RingBuffer*=lorenzo@google.com
-per-file RingBuffer*=satk@google.com
-per-file State*=ek@google.com
-per-file State*=lorenzo@google.com
-per-file State*=quiche@google.com
-per-file State*=silberst@google.com
-per-file TokenBucket*=ek@google.com
-per-file TokenBucket*=lorenzo@google.com
-per-file TokenBucket*=satk@google.com
+per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
+per-file BitUtils*, MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file Protocol* = etancohen@google.com, lorenzo@google.com
+per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 6f9c87a..ececba1 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -68,7 +69,7 @@
 
     @GuardedBy("mLock")
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private InputConnection mInputConnection;
 
     private Looper mMainLooper;
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index b6a654a..97d5a65 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -33,7 +33,7 @@
  * {@hide}
  */
 oneway interface IInputMethod {
-    void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps);
+    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
     void bindInput(in InputBinding binding);
 
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 0b37d57..4773e16 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -840,7 +840,11 @@
                 scale *= 10;
             }
             value = (float) (Math.rint(value * scale) / scale);
-            
+
+            // Corner case: (int)-0.1 will become zero, so the negative sign gets lost
+            if ((int) value == 0 && value < 0) {
+                append("-");
+            }
             append((int) value);
 
             if (precision != 0) {
diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
index 65be161..b2e8b5e 100644
--- a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
+++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -37,6 +37,7 @@
 import org.apache.http.params.HttpParams;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
@@ -181,7 +182,7 @@
     private final javax.net.ssl.SSLSocketFactory socketfactory;
     @UnsupportedAppUsage
     private final HostNameResolver nameResolver;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
 
     public SSLSocketFactory(
@@ -251,7 +252,7 @@
      * This constructor is used exclusively to instantiate the factory for
      * {@link #getSocketFactory getSocketFactory}.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private SSLSocketFactory() {
         super();
         this.sslcontext = null;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index bb8ee14..762b430 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -230,7 +230,6 @@
     static_libs: [
         "libgif",
         "libseccomp_policy",
-        "libselinux",
         "libgrallocusage",
         "libscrypt_static",
     ],
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6e661e1..3ead633 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,6 +72,9 @@
         // List of the accessibility services to which the user has granted
         // permission to put the device into touch exploration mode.
         optional SettingProto touch_exploration_granted_accessibility_services = 31;
+        optional SettingProto minimum_ui_timeout_enabled = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto minimum_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 25059be..8836c2e 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -72,7 +72,8 @@
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 hint = 1;
-    repeated ManagedServiceInfoProto listeners = 2;
+    reserved 2; // ManagedServiceInfoProto listeners
+    repeated android.content.ComponentNameProto listener_components = 3;
 }
 
 message ManagedServiceInfoProto {
@@ -199,6 +200,7 @@
     optional string condition_id = 8;
     optional ConditionProto condition = 9;
     optional android.content.ComponentNameProto component = 10;
+    optional ZenPolicyProto zenPolicy = 11;
 }
 
 // A dump from com.android.server.notification.ZenModeHelper.
@@ -211,3 +213,47 @@
     repeated android.content.ComponentNameProto suppressors = 4;
     optional android.app.PolicyProto policy = 5;
 }
+
+// An android.service.notification.ZenPolicy object
+message ZenPolicyProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    enum State {
+        STATE_UNSET = 0;
+        STATE_ALLOW = 1;
+        STATE_DISALLOW = 2;
+    }
+
+    // Notifications and sounds allowed/disallowed when DND is active
+    optional State reminders = 1;
+    optional State events = 2;
+    optional State messages = 3;
+    optional State calls = 4;
+    optional State repeat_callers = 5;
+    optional State alarms = 6;
+    optional State media = 7;
+    optional State system = 8;
+
+    // Visual effects allowed/disallowed for intercepted notifications when DND is active
+    optional State full_screen_intent = 9;
+    optional State lights = 10;
+    optional State peek = 11;
+    optional State status_bar = 12;
+    optional State badge= 13;
+    optional State ambient = 14;
+    optional State notification_list = 15;
+
+    enum Sender {
+        SENDER_UNSET = 0;
+        // Any sender is prioritized.
+        SENDER_ANY = 1;
+        // Saved contacts are prioritized.
+        SENDER_CONTACTS = 2;
+        // Only starred contacts are prioritized.
+        SENDER_STARRED = 3;
+        // No calls/messages are prioritized.
+        SENDER_NONE = 4;
+    }
+    optional Sender priority_calls = 16;
+    optional Sender priority_messages = 17;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9ab55d6..1df3f7f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3054,6 +3054,18 @@
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an app to reset the device password.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.RESET_PASSWORD"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Allows an app to lock the device.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.LOCK_DEVICE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows low-level access to setting the orientation (actually
          rotation) of the screen.
          <p>Not for use by third-party applications.
@@ -3756,6 +3768,10 @@
     <permission android:name="android.permission.USE_BIOMETRIC_INTERNAL"
         android:protectionLevel="signature" />
 
+    <!-- Allows the system to control the BiometricDialog (SystemUI). Reserved for the system. @hide -->
+    <permission android:name="android.permission.MANAGE_BIOMETRIC_DIALOG"
+        android:protectionLevel="signature" />
+
     <!-- Allows an app to reset face authentication attempt counter. Reserved for the system. @hide -->
     <permission android:name="android.permission.RESET_FACE_LOCKOUT"
         android:protectionLevel="signature" />
@@ -4112,7 +4128,7 @@
     <!-- Allows an application to directly open the "Open by default" page inside a package's
          Details screen.
          @hide <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.OPEN_APPLICATION_DETAILS_OPEN_BY_DEFAULT_PAGE"
+    <permission android:name="android.permission.OPEN_APP_OPEN_BY_DEFAULT_SETTINGS"
                 android:protectionLevel="signature" />
 
     <!-- Allows hidden API checks to be disabled when starting a process.
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6932be3..e153082 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'envoyer et d\'afficher des SMS ?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"accéder à des photos, à des contenus multimédias et à des fichiers sur votre appareil"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microphone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"enregistrer des fichiers audio"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'enregistrer des contenus audio ?"</string>
@@ -1340,7 +1340,7 @@
     <string name="ext_media_unmountable_notification_message" msgid="4193858924381066522">"Appuyez sur la notification pour résoudre le problème"</string>
     <string name="ext_media_unmountable_notification_message" product="tv" msgid="3941179940297874950">"La <xliff:g id="NAME">%s</xliff:g> est corrompue. Sélectionnez cette option pour résoudre le problème."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> non compatible"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec la mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec le support \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string>
     <string name="ext_media_unsupported_notification_message" product="tv" msgid="3725436899820390906">"Cet appareil n\'est pas compatible avec cette <xliff:g id="NAME">%s</xliff:g>. Sélectionnez cette option pour la configurer dans un format accepté."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Retrait inattendu de mémoire \"<xliff:g id="NAME">%s</xliff:g>\""</string>
     <string name="ext_media_badremoval_notification_message" msgid="8556885808951260574">"Éjectez le périphérique externe avant de le retirer pour éviter toute perte de contenu"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d4b800a..6afe603 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1895,10 +1895,10 @@
     <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
     <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
     <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
-    <string name="autofill_update_title" msgid="4879673117448810818">"&lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt;? में अपडेट करें?"</string>
-    <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को to &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+    <string name="autofill_update_title" msgid="4879673117448810818">"&lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+    <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
     <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
-    <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में अपडेट करें."</string>
+    <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
     <string name="autofill_save_yes" msgid="6398026094049005921">"सेव करें"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"नहीं, धन्यवाद"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करें"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 8b3f287..6a5f287 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -514,7 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string>
-    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարք չի գտնվել"</string>
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարքը հասանելի չէ"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Մատնահետքը հայտնաբերվել է մասամբ: Փորձեք նորից:"</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4cada60..4915111 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"SMS メッセージの送信と表示を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ストレージ"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"端末内の写真、メディア、ファイルへのアクセス"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"マイク"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"音声の録音"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index dca94ff..e228d35 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"ಎಸ್‌ಎಂಎಸ್‌ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ವೀಕ್ಷಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ಸಂಗ್ರಹಣೆ"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ, ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"ಮೈಕ್ರೋಫೋನ್‌"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 351f8ea..6bbd258 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -27,5 +27,5 @@
     <color name="notification_default_color_dark">#ddffffff</color>
 
     <!-- The background color of a notification card. -->
-    <color name="notification_material_background_color">@*android:color/material_grey_900</color>
+    <color name="notification_material_background_color">@color/black</color>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 4eb2ff3..45cf0f0 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -26,7 +26,7 @@
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
 
         <!-- QS panel background -->
-        <item name="colorBackgroundFloating">@color/material_grey_900</item>
+        <item name="colorBackgroundFloating">@color/black</item>
 
         <!-- volume background -->
         <item name="panelColorBackground">@color/material_grey_800</item>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e31f161..c14bce4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -290,7 +290,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправлять и просматривать SMS?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Хранилище"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению &lt;b&gt;\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"&lt;/b&gt; доступ к фото, мультимедиа и файлам на устройстве?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото, мультимедиа и файлам на устройстве?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"записывать аудио"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио?"</string>
@@ -305,7 +305,7 @@
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; совершать звонки и управлять ими?"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Нательные датчики"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"доступ к данным датчиков о состоянии организма"</string>
-    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению &lt;b&gt;\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"&lt;/b&gt; доступ к данным датчиков о состоянии организма?"</string>
+    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным датчиков о состоянии организма?"</string>
     <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string>
     <string name="permgroupdesc_aural" msgid="4870189506255958055">"доступ к музыке"</string>
     <string name="permgrouprequest_aural" msgid="6787926123071735620">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к музыке?"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 8b89a97..0f353f2 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -514,8 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවන්න"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string>
-    <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
-    <skip />
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string>
@@ -523,8 +522,7 @@
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ඇඟිල්ල වඩා සෙමෙන් ගෙන යන ලදි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
-    <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
-    <skip />
+    <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්‍යාපනය කරන ලදී"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index b175f75..35592a6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"மெசேஜ்களை அனுப்பவும், பார்க்கவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"சேமிப்பிடம்"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுக வேண்டும்"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; பயன்பாட்டை அனுமதிக்கவா?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"மைக்ரோஃபோன்"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ஒலிப் பதிவு செய்யலாம்"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ஆடியோவைப் பதிவு செய்ய &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; பயன்பாட்டை அனுமதிக்கவா?"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0b04e08..966a5a5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -272,9 +272,9 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的通讯录吗?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取此设备的位置信息吗?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string>
     <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"只有当您使用该应用时,该应用才有权获取位置信息。"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取此设备的位置信息吗?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"即使您并未使用该应用,该应用也将始终有权获取位置信息。"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"日历"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"访问您的日历"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bd4ea2a..bd36ed6 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -514,7 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改你的相片收藏。"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取你的媒體收藏的位置資訊"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string>
-    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"找不到生物特徵辨識硬體"</string>
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物特徵辨識硬體"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"僅偵測到部分指紋,請再試一次。"</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋,請再試一次。"</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3fed8a3..65b8807 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3573,6 +3573,11 @@
              {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
              android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
         <attr name="notificationTimeout" format="integer" />
+        <!-- The minimum timeout in milliseconds that UI controls need to remain on the screen.
+             This setting can be changed at runtime by calling
+             {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+             android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+        <attr name="minimumUiTimeout" format="integer" />
         <!-- Additional flags as specified in
              {@link android.accessibilityservice.AccessibilityServiceInfo}.
              This setting can be changed at runtime by calling
@@ -3601,6 +3606,8 @@
             <flag name="flagRequestAccessibilityButton" value="0x00000100" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES}. -->
             <flag name="flagRequestFingerprintGestures" value="0x00000200" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. -->
+            <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 293d90e..c4f68e3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -913,7 +913,7 @@
     <!--  Control whether to lock day/night mode change from normal application. When it is
           true, day / night mode change is only allowed to apps with MODIFY_DAY_NIGHT_MODE
           permission. -->
-    <bool name="config_lockDayNightMode">true</bool>
+    <bool name="config_lockDayNightMode">false</bool>
 
     <!-- Control the default night mode to use when there is no other mode override set.
          One of the following values (see UiModeManager.java):
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bf7e068..8bca211 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -172,4 +172,7 @@
 
     <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. -->
     <item type="id" name="accessibilityActionHideTooltip" />
+
+  <!-- Accessibility action to notify a window there is an outside touch. -->
+  <item type="id" name="accessibilityActionOutsideTouch" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fa31dce..c751af3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2914,6 +2914,7 @@
     <public-group type="attr" first-id="0x0101058d">
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
+        <public name="minimumUiTimeout" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e2">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 365e4a4..1a5b7b6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4334,6 +4334,9 @@
     <string name="accessibility_shortcut_disabling_service">Accessibility Shortcut turned
         <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string>
 
+    <!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] -->
+    <string name="accessibility_shortcut_spoken_feedback">Use Accessibility Shortcut again to start the current accessibility feature</string>
+
     <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. -->
     <string name="accessibility_button_prompt_text">Choose a feature to use when you tap the Accessibility button:</string>
 
diff --git a/core/res/res/values/styles_permission_controller.xml b/core/res/res/values/styles_permission_controller.xml
index 339f9c7..e6e0de3 100644
--- a/core/res/res/values/styles_permission_controller.xml
+++ b/core/res/res/values/styles_permission_controller.xml
@@ -15,8 +15,8 @@
   limitations under the License.
   -->
 
-<!-- styles for the permission grant dialog. -->
 <resources>
+    <!-- styles for the permission grant dialog. -->
     <style name="PermissionGrantDialog">
         <item name="background">?attr/windowBackground</item>
         <item name="elevation">?attr/windowElevation</item>
@@ -95,4 +95,37 @@
         <item name="layout_marginEnd">16dp</item>
         <item name="layout_marginBottom">4dp</item>
     </style>
+
+    <!-- styles for the permission review screen. -->
+    <style name="PermissionReviewDescription">
+        <item name="layout_marginTop">20dp</item>
+        <item name="layout_marginStart">24dp</item>
+        <item name="layout_marginBottom">16dp</item>
+        <item name="layout_marginEnd">24dp</item>
+    </style>
+
+    <style name="PermissionReviewTitleIcon">
+        <item name="layout_marginTop">4dp</item>
+        <item name="layout_width">36dp</item>
+        <item name="layout_height">36dp</item>
+        <item name="scaleType">fitCenter</item>
+    </style>
+
+    <style name="PermissionReviewTitleMessage"
+           parent="@style/TextAppearance.DeviceDefault">
+        <item name="paddingStart">22dp</item>
+        <item name="textSize">20sp</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+    </style>
+
+    <style name="PermissionReviewSettings">
+        <item name="layout_marginStart">8dp</item>
+        <item name="layout_marginEnd">8dp</item>
+    </style>
+
+    <style name="PermissionReviewButtonBar">
+        <item name="layout_marginStart">24dp</item>
+        <item name="layout_marginEnd">16dp</item>
+        <item name="layout_marginBottom">4dp</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 389278f..7b8eced 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,6 +218,7 @@
   <java-symbol type="id" name="selection_end_handle" />
   <java-symbol type="id" name="insertion_handle" />
   <java-symbol type="id" name="accessibilityActionClickOnClickableSpan" />
+  <java-symbol type="id" name="accessibilityActionOutsideTouch" />
   <java-symbol type="id" name="camera" />
   <java-symbol type="id" name="mic" />
   <java-symbol type="id" name="overlay" />
@@ -3082,6 +3083,7 @@
   <java-symbol type="string" name="color_inversion_feature_name" />
   <java-symbol type="string" name="color_correction_feature_name" />
   <java-symbol type="string" name="config_defaultAccessibilityService" />
+  <java-symbol type="string" name="accessibility_shortcut_spoken_feedback" />
 
   <!-- Accessibility Button -->
   <java-symbol type="layout" name="accessibility_button_chooser" />
diff --git a/core/res/res/values/themes_permission_controller.xml b/core/res/res/values/themes_permission_controller.xml
index 3bc93cd..369cee3 100644
--- a/core/res/res/values/themes_permission_controller.xml
+++ b/core/res/res/values/themes_permission_controller.xml
@@ -15,8 +15,8 @@
   limitations under the License.
   -->
 
-<!-- themes for the permission grant dialog. -->
 <resources>
+    <!-- themes for the permission grant dialog. -->
     <style name="Theme.DeviceDefault.PermissionGrantApp"
            parent="@style/Theme.DeviceDefault.Light.Panel">
         <item name="windowIsFloating">false</item>
@@ -32,4 +32,13 @@
         <item name="checkboxStyle">@style/PermissionGrantCheckbox</item>
         <item name="buttonBarStyle">@style/PermissionGrantButtonBar</item>
     </style>
+
+    <!-- themes for the permission review dialog. -->
+    <style name="Theme.DeviceDefault.PermissionReviewApp"
+           parent="@style/Theme.DeviceDefault.Settings">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="titleTextStyle">@style/PermissionReviewTitleMessage</item>
+        <item name="buttonBarStyle">@style/PermissionReviewButtonBar</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
new file mode 100644
index 0000000..7218b3a2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.content.pm;
+
+import static android.content.pm.PackageBuilder.builder;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.os.Build;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O);
+
+        // Should add both HIDL libraries
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(OTHER_LIBRARY);
+
+        // The hidl jars should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        PackageBuilder before = builder()
+                .targetSdkVersion(Build.VERSION_CODES.O)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        // No change is required because although the HIDL libraries has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, before);
+    }
+
+    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
+        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 2f28606..b5ed01f 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -186,44 +186,28 @@
         Paint p = new Paint();
 
         final int count = end - start;
-        final float[][] advanceArrays = new float[4][count];
-
-        final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
-                isRtl, advanceArrays[0], 0);
-
+        final int contextCount = contextEnd - contextStart;
+        final float[][] advanceArrays = new float[2][count];
         char chars[] = str.toCharArray();
-        final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
-                contextEnd - contextStart, isRtl, advanceArrays[1], 0);
-        assertEquals(advance, advance_c, 1.0f);
-
+        final float advance = p.getTextRunAdvances(chars, start, count,
+                contextStart, contextCount, isRtl, advanceArrays[0], 0);
         for (int c = 1; c < count; ++c) {
-            final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
-                    contextStart, contextEnd, isRtl, advanceArrays[2], 0);
-            final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
-                    contextStart, contextEnd, isRtl, advanceArrays[2], c);
+            final float firstPartAdvance = p.getTextRunAdvances(chars, start, c,
+                    contextStart, contextCount, isRtl, advanceArrays[1], 0);
+            final float secondPartAdvance = p.getTextRunAdvances(chars, start + c, count - c,
+                    contextStart, contextCount, isRtl, advanceArrays[1], c);
             assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
 
-
-            final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
-                    contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
-            final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
-                    count - c, contextStart, contextEnd - contextStart, isRtl,
-                    advanceArrays[3], c);
-            assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
-            assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
-            assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
-
-            for (int i = 1; i < advanceArrays.length; i++) {
-                for (int j = 0; j < count; j++) {
-                    assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
-                }
+            for (int j = 0; j < count; j++) {
+                assertEquals(advanceArrays[0][j], advanceArrays[1][j], 1.0f);
             }
 
+
             // Compare results with measureText, getRunAdvance, and getTextWidths.
             if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
                 assertEquals(advance, p.measureText(str, start, end), 1.0f);
                 assertEquals(advance, p.getRunAdvance(
-                        str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
+                        chars, start, count, contextStart, contextCount, isRtl, end), 1.0f);
 
                 final float[] widths = new float[count];
                 p.getTextWidths(str, start, end, widths);
@@ -236,19 +220,7 @@
 
     public void testGetTextRunAdvances_invalid() {
         Paint p = new Paint();
-        String text = "test";
-
-        try {
-            p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
-            fail("Should throw an IllegalArgumentException.");
-        } catch (IllegalArgumentException e) {
-        }
+        char[] text = "test".toCharArray();
 
         try {
             p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
@@ -257,50 +229,43 @@
         }
 
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
-                    new float[text.length() - 1], 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
+                    new float[text.length - 1], 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
-                    new float[text.length()], 1);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
+                    new float[text.length], 1);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // 0 > contextStart
         try {
-            p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, -1, text.length, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // contextStart > start
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
-            fail("Should throw an IndexOutOfBoundsException.");
-        } catch (IndexOutOfBoundsException e) {
-        }
-
-        // start > end
-        try {
-            p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 1, text.length, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // end > contextEnd
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length - 1, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
 
         // contextEnd > text.length
         try {
-            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
+            p.getTextRunAdvances(text, 0, text.length, 0, text.length + 1, false, null, 0);
             fail("Should throw an IndexOutOfBoundsException.");
         } catch (IndexOutOfBoundsException e) {
         }
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 1c4039b..3ce2589 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -44,7 +44,7 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.HashSet;
+import java.util.ArrayList;
 import java.util.Locale;
 
 @SmallTest
@@ -112,7 +112,7 @@
 
     private static void buildSystemFallback(String xml,
             ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
             fos.write(xml.getBytes(Charset.forName("UTF-8")));
         } catch (IOException e) {
@@ -127,7 +127,7 @@
     public void testBuildSystemFallback() {
         final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
 
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
                 SYSTEM_FONT_DIR, fallbackMap, availableFonts);
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 9c9f11b..20fe162 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -17,6 +17,22 @@
 package android.os;
 
 import static android.os.FileUtils.roundStorageSize;
+import static android.os.FileUtils.translateModePfdToPosix;
+import static android.os.FileUtils.translateModePosixToPfd;
+import static android.os.FileUtils.translateModePosixToString;
+import static android.os.FileUtils.translateModeStringToPosix;
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_RDWR;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -476,6 +492,32 @@
         assertEquals(G64, roundStorageSize(G32 + 1));
     }
 
+    @Test
+    public void testTranslateMode() throws Exception {
+        assertTranslate("r", O_RDONLY, MODE_READ_ONLY);
+
+        assertTranslate("rw", O_RDWR | O_CREAT,
+                MODE_READ_WRITE | MODE_CREATE);
+        assertTranslate("rwt", O_RDWR | O_CREAT | O_TRUNC,
+                MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
+        assertTranslate("rwa", O_RDWR | O_CREAT | O_APPEND,
+                MODE_READ_WRITE | MODE_CREATE | MODE_APPEND);
+
+        assertTranslate("w", O_WRONLY | O_CREAT,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_CREATE);
+        assertTranslate("wt", O_WRONLY | O_CREAT | O_TRUNC,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_TRUNCATE);
+        assertTranslate("wa", O_WRONLY | O_CREAT | O_APPEND,
+                MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
+    }
+
+    private static void assertTranslate(String string, int posix, int pfd) {
+        assertEquals(posix, translateModeStringToPosix(string));
+        assertEquals(string, translateModePosixToString(posix));
+        assertEquals(pfd, translateModePosixToPfd(posix));
+        assertEquals(posix, translateModePfdToPosix(pfd));
+    }
+
     private static void assertNameEquals(String expected, File actual) {
         assertEquals(expected, actual.getName());
     }
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 355be61..898e78c 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -33,7 +33,7 @@
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
-import java.util.HashSet;
+import java.util.ArrayList;
 
 public class FontFallbackSetup implements AutoCloseable {
     private final String[] mTestFontFiles;
@@ -76,7 +76,7 @@
         }
 
         final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
                 mTestFontsDir, fallbackMap, availableFonts);
         Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index f3e10e0..a302657 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -16,6 +16,31 @@
 
 package com.android.internal.accessibility;
 
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.fail;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.AlertDialog;
 import android.content.ComponentName;
@@ -25,11 +50,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
+import android.media.Ringtone;
 import android.os.Handler;
+import android.os.Message;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.Voice;
 import android.support.test.runner.AndroidJUnit4;
-
 import android.test.mock.MockContentResolver;
 import android.text.TextUtils;
 import android.view.Window;
@@ -37,9 +65,10 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
+
 import com.android.internal.R;
-import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
+import com.android.internal.util.test.FakeSettingsProvider;
 
 import org.junit.After;
 import org.junit.Before;
@@ -48,31 +77,12 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
 
 import java.lang.reflect.Field;
 import java.util.Collections;
 import java.util.Map;
 
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.fail;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
 
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityShortcutControllerTest {
@@ -102,6 +112,9 @@
     private @Mock Vibrator mVibrator;
     private @Mock ApplicationInfo mApplicationInfo;
     private @Mock PackageManager mPackageManager;
+    private @Mock TextToSpeech mTextToSpeech;
+    private @Mock Voice mVoice;
+    private @Mock Ringtone mRingtone;
 
     private MockContentResolver mContentResolver;
     private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
@@ -137,6 +150,9 @@
         when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
                 .thenReturn(mToast);
         when(mFrameworkObjectProvider.getSystemUiContext()).thenReturn(mContext);
+        when(mFrameworkObjectProvider.getTextToSpeech(eq(mContext), any()))
+                .thenReturn(mTextToSpeech);
+        when(mFrameworkObjectProvider.getRingtone(eq(mContext), any())).thenReturn(mRingtone);
 
         when(mResources.getString(anyInt())).thenReturn("Howdy %s");
         when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
@@ -172,6 +188,8 @@
             throw new RuntimeException("Unable to set mWindowAttributes", e);
         }
         when(mAlertDialog.getWindow()).thenReturn(window);
+
+        when(mTextToSpeech.getVoice()).thenReturn(mVoice);
     }
 
     @After
@@ -308,8 +326,10 @@
                 mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
         verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning);
         verify(mAlertDialog).show();
-        verify(mAccessibilityManagerService).getInstalledAccessibilityServiceList(anyInt());
+        verify(mAccessibilityManagerService, atLeastOnce()).getInstalledAccessibilityServiceList(
+                anyInt());
         verify(mAccessibilityManagerService, times(0)).performAccessibilityShortcut();
+        verify(mFrameworkObjectProvider, times(0)).getTextToSpeech(any(), any());
     }
 
     @Test
@@ -434,6 +454,49 @@
         verify(mAccessibilityManagerService).performAccessibilityShortcut();
     }
 
+    @Test
+    public void testOnAccessibilityShortcut_showsWarningDialog_shouldTtsSpokenPrompt() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        configureTtsSpokenPromptEnabled();
+        configureHandlerCallbackInvocation();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        verify(mAlertDialog).show();
+        ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass(
+                TextToSpeech.OnInitListener.class);
+        verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture());
+        onInitCap.getValue().onInit(TextToSpeech.SUCCESS);
+        verify(mTextToSpeech).speak(any(), eq(TextToSpeech.QUEUE_FLUSH), any(), any());
+        ArgumentCaptor<DialogInterface.OnDismissListener> onDismissCap = ArgumentCaptor.forClass(
+                DialogInterface.OnDismissListener.class);
+        verify(mAlertDialog).setOnDismissListener(onDismissCap.capture());
+        onDismissCap.getValue().onDismiss(mAlertDialog);
+        verify(mTextToSpeech).shutdown();
+        verify(mRingtone, times(0)).play();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_showsWarningDialog_ttsInitFail_noSpokenPrompt() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        configureTtsSpokenPromptEnabled();
+        configureHandlerCallbackInvocation();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        verify(mAlertDialog).show();
+        ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass(
+                TextToSpeech.OnInitListener.class);
+        verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture());
+        onInitCap.getValue().onInit(TextToSpeech.ERROR);
+        verify(mTextToSpeech, times(0)).speak(any(), anyInt(), any(), any());
+        verify(mRingtone).play();
+    }
+
     private void configureNoShortcutService() {
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
     }
@@ -481,6 +544,19 @@
                 mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
     }
 
+    private void configureTtsSpokenPromptEnabled() {
+        mServiceInfo.flags |= AccessibilityServiceInfo
+                .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK;
+    }
+
+    private void configureHandlerCallbackInvocation() {
+        doAnswer((InvocationOnMock invocation) -> {
+            Message m = (Message) invocation.getArguments()[0];
+            m.getCallback().run();
+            return true;
+        }).when(mHandler).sendMessageAtTime(any(), anyLong());
+    }
+
     private AccessibilityShortcutController getController() {
         AccessibilityShortcutController accessibilityShortcutController =
                 new AccessibilityShortcutController(mContext, mHandler, 0);
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
new file mode 100644
index 0000000..8179328
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.internal.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SubtypeLocaleUtilsTest {
+    private static final Locale LOCALE_EN = new Locale("en");
+    private static final Locale LOCALE_EN_US = new Locale("en", "US");
+    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
+    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_JA = new Locale("ja");
+    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
+    private static final Locale LOCALE_TH = new Locale("ht");
+    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
+    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
+
+    @Test
+    public void testConstructLocaleFromString() throws Exception {
+        assertEquals(new Locale("en"), SubtypeLocaleUtils.constructLocaleFromString("en"));
+        assertEquals(new Locale("en", "US"), SubtypeLocaleUtils.constructLocaleFromString("en_US"));
+        assertEquals(new Locale("en", "US", "POSIX"),
+                SubtypeLocaleUtils.constructLocaleFromString("en_US_POSIX"));
+
+        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
+        // support three letter language codes, and used "tl" (Tagalog) as the language string for
+        // "fil" (Filipino).
+        assertEquals(new Locale("fil"), SubtypeLocaleUtils.constructLocaleFromString("tl"));
+        assertEquals(new Locale("fil", "PH"),
+                SubtypeLocaleUtils.constructLocaleFromString("tl_PH"));
+        assertEquals(new Locale("fil", "PH", "POSIX"),
+                SubtypeLocaleUtils.constructLocaleFromString("tl_PH_POSIX"));
+
+        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
+        assertEquals(new Locale("a"), SubtypeLocaleUtils.constructLocaleFromString("a"));
+        assertEquals(new Locale("a b c"), SubtypeLocaleUtils.constructLocaleFromString("a b c"));
+        assertEquals(new Locale("en-US"), SubtypeLocaleUtils.constructLocaleFromString("en-US"));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0eb3d06..565a3ec 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -342,6 +342,20 @@
         assertThat(looperStats.getEntries().get(0).messageCount).isEqualTo(2);
     }
 
+    @Test
+    public void testReset() {
+        TestableLooperStats looperStats = new TestableLooperStats(1, 1);
+
+        Object token1 = looperStats.messageDispatchStarting();
+        looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000));
+        Object token2 = looperStats.messageDispatchStarting();
+        looperStats.messageDispatched(token2, mHandlerFirst.obtainMessage(2000));
+        looperStats.reset();
+
+        List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+        assertThat(entries).hasSize(0);
+    }
+
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
         try {
             r.run();
diff --git a/core/tests/webkit/Android.mk b/core/tests/webkit/Android.mk
deleted file mode 100644
index 45f6957..0000000
--- a/core/tests/webkit/Android.mk
+++ /dev/null
@@ -1,45 +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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
-	$(call all-java-files-under, unit_tests_src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	android-support-test
-
-LOCAL_PACKAGE_NAME := WebViewLoadingTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_REQUIRED_MODULES := \
-	WebViewLoadingOnDiskTestApk \
-	WebViewLoadingFromApkTestApk
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/webkit/AndroidManifest.xml b/core/tests/webkit/AndroidManifest.xml
deleted file mode 100644
index 42accdf..0000000
--- a/core/tests/webkit/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.webkit.tests"
-          android:sharedUserId="android.uid.system">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation
-            android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.webkit.tests"
-            android:label="Frameworks WebView Loader Tests" />
-
-</manifest>
diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml
deleted file mode 100644
index 4c50b7d..0000000
--- a/core/tests/webkit/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Runs Frameworks WebView Loading Tests.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-instrumentation" />
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="test-file-name" value="WebViewLoadingTests.apk" />
-        <option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" />
-        <option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" />
-        <option name="cleanup-apks" value="true" />
-        <option name="alt-dir" value="out" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.webkit.tests" />
-    </test>
-</configuration>
diff --git a/core/tests/webkit/OWNERS b/core/tests/webkit/OWNERS
deleted file mode 100644
index 00e540a..0000000
--- a/core/tests/webkit/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-changwan@google.com
-tobiasjs@google.com
-torne@google.com
diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk
deleted file mode 100644
index e18a7e0..0000000
--- a/core/tests/webkit/apk_with_native_libs/Android.mk
+++ /dev/null
@@ -1,71 +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.
-
-LOCAL_PATH := $(call my-dir)
-MY_PATH := $(LOCAL_PATH)
-
-# Set shared variables
-MY_MODULE_TAGS := optional
-MY_JNI_SHARED_LIBRARIES := libwebviewtest_jni
-MY_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-MY_SRC_FILES := $(call all-java-files-under, src)
-MY_CFLAGS := -Wall -Werror
-MY_SDK_VERSION := system_current
-MY_PROGUARD_ENABLED := disabled
-MY_MULTILIB := both
-
-# Recurse down the file tree.
-include $(call all-subdir-makefiles)
-
-
-
-# Builds an apk containing native libraries that will be unzipped on the device.
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(MY_PATH)
-LOCAL_PACKAGE_NAME := WebViewLoadingOnDiskTestApk
-LOCAL_MANIFEST_FILE := ondisk/AndroidManifest.xml
-
-LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
-LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
-LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
-LOCAL_SRC_FILES := $(MY_SRC_FILES)
-LOCAL_CFLAGS := $(MY_CFLAGS)
-LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
-LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
-LOCAL_MULTILIB := $(MY_MULTILIB)
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-
-# Builds an apk containing uncompressed native libraries that have to be
-# accessed through the APK itself on the device.
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(MY_PATH)
-LOCAL_PACKAGE_NAME := WebViewLoadingFromApkTestApk
-LOCAL_MANIFEST_FILE := inapk/AndroidManifest.xml
-
-LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
-LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
-LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
-LOCAL_SRC_FILES := $(MY_SRC_FILES)
-LOCAL_CFLAGS := $(MY_CFLAGS)
-LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
-LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
-LOCAL_MULTILIB := $(MY_MULTILIB)
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml
deleted file mode 100644
index 868b238..0000000
--- a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.webviewloading_test_from_apk"
-    android:versionCode="1"
-    android:versionName="0.0.0.1">
-
-    <application android:label="WebView Loading Test APK"
-      android:multiArch="true"
-      android:extractNativeLibs="false">
-        <meta-data android:name="com.android.webview.WebViewLibrary"
-            android:value="libwebviewtest_jni.so" />
-    </application>
-</manifest>
diff --git a/core/tests/webkit/apk_with_native_libs/jni/Android.mk b/core/tests/webkit/apk_with_native_libs/jni/Android.mk
deleted file mode 100644
index fd5b5eb..0000000
--- a/core/tests/webkit/apk_with_native_libs/jni/Android.mk
+++ /dev/null
@@ -1,32 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libwebviewtest_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := WebViewTestJniOnLoad.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp b/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
deleted file mode 100644
index 0ced4ee..0000000
--- a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
+++ /dev/null
@@ -1,21 +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.
- */
-
-#include <jni.h>
-
-jint JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/) {
-    return JNI_VERSION_1_4;
-}
diff --git a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml
deleted file mode 100644
index ffffeb8..0000000
--- a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.webviewloading_test_on_disk"
-    android:versionCode="1"
-    android:versionName="0.0.0.1">
-
-    <application android:label="WebView Loading Test APK"
-      android:multiArch="true">
-        <meta-data android:name="com.android.webview.WebViewLibrary"
-            android:value="libwebviewtest_jni.so" />
-    </application>
-</manifest>
diff --git a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java b/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java
deleted file mode 100644
index 0efa4b4..0000000
--- a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java
+++ /dev/null
@@ -1,24 +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 com.android.webview.chromium;
-
-/**
- * An empty class for testing purposes.
- */
-public class WebViewLoadingTestClass {
-}
diff --git a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java b/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java
deleted file mode 100644
index e2f2d37..0000000
--- a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java
+++ /dev/null
@@ -1,329 +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.webkit;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Unit tests for {@link WebViewLibraryLoader}.
- * Use the following command to run these tests:
- * make WebViewLoadingTests \
- * && adb install -r -d \
- * ${ANDROID_PRODUCT_OUT}/data/app/WebViewLoadingTests/WebViewLoadingTests.apk \
- * && adb shell am instrument -e class 'android.webkit.WebViewLibraryLoaderTest' -w \
- * 'com.android.webkit.tests/android.support.test.runner.AndroidJUnitRunner'
- */
-@RunWith(AndroidJUnit4.class)
-public final class WebViewLibraryLoaderTest {
-    private static final String WEBVIEW_LIBS_ON_DISK_TEST_APK =
-            "com.android.webviewloading_test_on_disk";
-    private static final String WEBVIEW_LIBS_IN_APK_TEST_APK =
-            "com.android.webviewloading_test_from_apk";
-    private static final String WEBVIEW_LOADING_TEST_NATIVE_LIB = "libwebviewtest_jni.so";
-
-    private PackageInfo webviewOnDiskPackageInfo;
-    private PackageInfo webviewFromApkPackageInfo;
-
-    @Before public void setUp() throws PackageManager.NameNotFoundException {
-        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
-        webviewOnDiskPackageInfo =
-                pm.getPackageInfo(WEBVIEW_LIBS_ON_DISK_TEST_APK, PackageManager.GET_META_DATA);
-        webviewFromApkPackageInfo =
-                pm.getPackageInfo(WEBVIEW_LIBS_IN_APK_TEST_APK, PackageManager.GET_META_DATA);
-    }
-
-    private static boolean is64BitDevice() {
-        return Build.SUPPORTED_64_BIT_ABIS.length > 0;
-    }
-
-    // We test the getWebViewNativeLibraryDirectory method here because it handled several different
-    // cases/combinations and it seems unnecessary to create one test-apk for each such combination
-    // and arch.
-
-    /**
-     * Ensure we fetch the correct native library directories in the multi-arch case where
-     * the primary ABI is 64-bit.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirMultiArchPrimary64bit() {
-        final String nativeLib = "nativeLib";
-        final String secondaryNativeLib = "secondaryNativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("arm64-v8a").
-                setNativeLibraryDir(nativeLib).
-                setSecondaryCpuAbi("armeabi").
-                setSecondaryNativeLibraryDir(secondaryNativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual32Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */);
-        String actual64Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */);
-        assertEquals(nativeLib, actual64Lib);
-        assertEquals(secondaryNativeLib, actual32Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct native library directory in the 64-bit single-arch case.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirSingleArch64bit() {
-        final String nativeLib = "nativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("arm64-v8a").
-                setNativeLibraryDir(nativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual64Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */);
-        assertEquals(nativeLib, actual64Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct native library directory in the 32-bit single-arch case.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirSingleArch32bit() {
-        final String nativeLib = "nativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("armeabi-v7a").
-                setNativeLibraryDir(nativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual32Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */);
-        assertEquals(nativeLib, actual32Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebViewLibraryPathOnDisk32Bit()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, false /* is64bit */);
-        String expectedLibaryDirectory = is64BitDevice() ?
-                webviewOnDiskPackageInfo.applicationInfo.secondaryNativeLibraryDir :
-                webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir;
-        String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        assertEquals("Fetched incorrect 32-bit path from WebView library.",
-                lib32Path, actualNativeLib.path);
-    }
-
-    /**
-     * Ensure we fetch the correct 64-bit library path from an APK with 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebViewLibraryPathOnDisk64Bit()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, true /* is64bit */);
-        String lib64Path = webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir
-                + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        assertEquals("Fetched incorrect 64-bit path from WebView library.",
-                lib64Path, actualNativeLib.path);
-    }
-
-    /**
-     * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibrarySizeOnDiskIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, false /* is64bit */);
-        assertTrue(actual32BitNativeLib.size > 0);
-    }
-
-    /**
-     * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibrarySizeOnDiskIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-        WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, true /* is64bit */);
-        assertTrue(actual64BitNativeLib.size > 0);
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibraryPathFromApk()
-            throws WebViewFactory.MissingWebViewPackageException, IOException {
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, false /* is64bit */);
-        // The device might have ignored the app's request to not extract native libs, so first
-        // check whether the library paths match those of extracted libraries.
-        String expectedLibaryDirectory = is64BitDevice() ?
-                webviewFromApkPackageInfo.applicationInfo.secondaryNativeLibraryDir :
-                webviewFromApkPackageInfo.applicationInfo.nativeLibraryDir;
-        String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        if (lib32Path.equals(actualNativeLib.path)) {
-            // If the libraries were extracted to disk, ensure that they're actually there.
-            assertTrue("The given WebView library doesn't exist.",
-                    new File(actualNativeLib.path).exists());
-        } else { // The libraries were not extracted to disk.
-            assertIsValidZipEntryPath(actualNativeLib.path,
-                    webviewFromApkPackageInfo.applicationInfo.sourceDir);
-        }
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibraryPathFromApk()
-            throws WebViewFactory.MissingWebViewPackageException, IOException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, true /* is64bit */);
-        assertIsValidZipEntryPath(actualNativeLib.path,
-                webviewFromApkPackageInfo.applicationInfo.sourceDir);
-    }
-
-    private static void assertIsValidZipEntryPath(String path, String zipFilePath)
-            throws IOException {
-        assertTrue("The path to a zip entry must start with the path to the zip file itself."
-            + "Expected zip path: " + zipFilePath + ", actual zip entry: " + path,
-            path.startsWith(zipFilePath + "!/"));
-        String[] pathSplit = path.split("!/");
-        assertEquals("A zip file path should have two parts, the zip path, and the zip entry path.",
-                2, pathSplit.length);
-        ZipFile zipFile = new ZipFile(pathSplit[0]);
-        assertNotNull("Path doesn't point to a valid zip entry: " + path,
-                zipFile.getEntry(pathSplit[1]));
-    }
-
-
-    /**
-     * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibrarySizeFromApkIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, false /* is64bit */);
-        assertTrue(actual32BitNativeLib.size > 0);
-    }
-
-    /**
-     * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibrarySizeFromApkIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, true /* is64bit */);
-        assertTrue(actual64BitNativeLib.size > 0);
-    }
-
-    private static class ApplicationInfoBuilder {
-        ApplicationInfo ai;
-
-        public ApplicationInfoBuilder setPrimaryCpuAbi(String primaryCpuAbi) {
-            ai.primaryCpuAbi = primaryCpuAbi;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setSecondaryCpuAbi(String secondaryCpuAbi) {
-            ai.secondaryCpuAbi = secondaryCpuAbi;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setNativeLibraryDir(String nativeLibraryDir) {
-            ai.nativeLibraryDir = nativeLibraryDir;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setSecondaryNativeLibraryDir(
-                String secondaryNativeLibraryDir) {
-            ai.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setMetaData(Bundle metaData) {
-            ai.metaData = metaData;
-            return this;
-        }
-
-        public ApplicationInfoBuilder() {
-            ai = new android.content.pm.ApplicationInfo();
-        }
-
-        public ApplicationInfo create() {
-            return ai;
-        }
-    }
-}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6f52fbd..c4017d1 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -188,6 +188,12 @@
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.impl.jar" />
 
+    <!-- In BOOT_JARS historically, and now added to legacy applications. -->
+    <library name="android.hidl.base-V1.0-java"
+            file="/system/framework/android.hidl.base-V1.0-java.jar" />
+    <library name="android.hidl.manager-V1.0-java"
+            file="/system/framework/android.hidl.manager-V1.0-java.jar" />
+
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save package="com.android.providers.downloads" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 616a8d6..114c228 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -281,6 +281,7 @@
         <permission name="android.permission.MANAGE_FINGERPRINT"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+        <permission name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.sharedstoragebackup">
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 9b5027d..43282d3 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -17,6 +17,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
+import android.os.Build;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -166,7 +167,7 @@
 
         This can be called from JNI code.
     */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private BitmapRegionDecoder(long decoder) {
         mNativeBitmapRegionDecoder = decoder;
         mRecycled = false;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ef58c8f..36c1c21 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -126,7 +126,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Canvas(long nativeCanvas) {
         if (nativeCanvas == 0) {
             throw new IllegalStateException();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 8162544..6f030ff 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetManager;
+import android.os.Build;
 
 import java.io.FileInputStream;
 import java.io.InputStream;
@@ -30,7 +31,7 @@
     @UnsupportedAppUsage
     private long mNativeMovie;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Movie(long nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6f30653..85b39fe 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,7 +17,9 @@
 package android.graphics;
 
 import android.annotation.ColorInt;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.Px;
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
@@ -2325,17 +2327,53 @@
     }
 
     /**
-     * Convenience overload that takes a char array instead of a
-     * String.
+     * Retrieve the character advances of the text.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
-     * @hide
+     * Returns the total advance width for the characters in the run from {@code index} for
+     * {@code count} of chars, and if {@code advances} is not null, the advance assigned to each of
+     * these characters (java chars).
+     *
+     * <p>
+     * The trailing surrogate in a valid surrogate pair is assigned an advance of 0.  Thus the
+     * number of returned advances is always equal to count, not to the number of unicode codepoints
+     * represented by the run.
+     * </p>
+     *
+     * <p>
+     * In the case of conjuncts or combining marks, the total advance is assigned to the first
+     * logical character, and the following characters are assigned an advance of 0.
+     * </p>
+     *
+     * <p>
+     * This generates the sum of the advances of glyphs for characters in a reordered cluster as the
+     * width of the first logical character in the cluster, and 0 for the widths of all other
+     * characters in the cluster.  In effect, such clusters are treated like conjuncts.
+     * </p>
+     *
+     * <p>
+     * The shaping bounds limit the amount of context available outside start and end that can be
+     * used for shaping analysis.  These bounds typically reflect changes in bidi level or font
+     * metrics across which shaping does not occur.
+     * </p>
+     *
+     * @param chars the text to measure.
+     * @param index the index of the first character to measure
+     * @param count the number of characters to measure
+     * @param contextIndex the index of the first character to use for shaping context.
+     *                     Context must cover the measureing target.
+     * @param contextCount the number of character to use for shaping context.
+     *                     Context must cover the measureing target.
+     * @param isRtl whether the run is in RTL direction
+     * @param advances array to receive the advances, must have room for all advances.
+     *                 This can be null if only total advance is needed
+     * @param advancesIndex the position in advances at which to put the advance corresponding to
+     *                      the character at start
+     * @return the total advance in pixels
      */
-    @UnsupportedAppUsage
-    public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, boolean isRtl, float[] advances,
-            int advancesIndex) {
-
+    public float getTextRunAdvances(@NonNull char[] chars, @IntRange(from = 0) int index,
+            @IntRange(from = 0) int count, @IntRange(from = 0) int contextIndex,
+            @IntRange(from = 0) int contextCount, boolean isRtl, @Nullable float[] advances,
+            @IntRange(from = 0) int advancesIndex) {
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2372,131 +2410,6 @@
     }
 
     /**
-     * Convenience overload that takes a CharSequence instead of a
-     * String.
-     *
-     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
-     * @hide
-     */
-    public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, boolean isRtl, float[] advances,
-            int advancesIndex) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
-                | (start - contextStart) | (contextEnd - end)
-                | (text.length() - contextEnd)
-                | (advances == null ? 0 :
-                    (advances.length - advancesIndex - (end - start)))) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (text instanceof String) {
-            return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex);
-        }
-        if (text instanceof SpannedString ||
-            text instanceof SpannableString) {
-            return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex);
-        }
-        if (text instanceof GraphicsOperations) {
-            return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex, this);
-        }
-        if (text.length() == 0 || end == start) {
-            return 0f;
-        }
-
-        int contextLen = contextEnd - contextStart;
-        int len = end - start;
-        char[] buf = TemporaryBuffer.obtain(contextLen);
-        TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, isRtl, advances, advancesIndex);
-        TemporaryBuffer.recycle(buf);
-        return result;
-    }
-
-    /**
-     * Returns the total advance width for the characters in the run
-     * between start and end, and if advances is not null, the advance
-     * assigned to each of these characters (java chars).
-     *
-     * <p>The trailing surrogate in a valid surrogate pair is assigned
-     * an advance of 0.  Thus the number of returned advances is
-     * always equal to count, not to the number of unicode codepoints
-     * represented by the run.
-     *
-     * <p>In the case of conjuncts or combining marks, the total
-     * advance is assigned to the first logical character, and the
-     * following characters are assigned an advance of 0.
-     *
-     * <p>This generates the sum of the advances of glyphs for
-     * characters in a reordered cluster as the width of the first
-     * logical character in the cluster, and 0 for the widths of all
-     * other characters in the cluster.  In effect, such clusters are
-     * treated like conjuncts.
-     *
-     * <p>The shaping bounds limit the amount of context available
-     * outside start and end that can be used for shaping analysis.
-     * These bounds typically reflect changes in bidi level or font
-     * metrics across which shaping does not occur.
-     *
-     * @param text the text to measure. Cannot be null.
-     * @param start the index of the first character to measure
-     * @param end the index past the last character to measure
-     * @param contextStart the index of the first character to use for shaping context,
-     * must be <= start
-     * @param contextEnd the index past the last character to use for shaping context,
-     * must be >= end
-     * @param isRtl whether the run is in RTL direction
-     * @param advances array to receive the advances, must have room for all advances,
-     * can be null if only total advance is needed
-     * @param advancesIndex the position in advances at which to put the
-     * advance corresponding to the character at start
-     * @return the total advance
-     *
-     * @hide
-     */
-    public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
-        if (text == null) {
-            throw new IllegalArgumentException("text cannot be null");
-        }
-        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
-                | (start - contextStart) | (contextEnd - end)
-                | (text.length() - contextEnd)
-                | (advances == null ? 0 :
-                    (advances.length - advancesIndex - (end - start)))) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (text.length() == 0 || start == end) {
-            return 0f;
-        }
-
-        if (!mHasCompatScaling) {
-            return nGetTextAdvances(mNativePaint, text, start, end, contextStart, contextEnd,
-                    isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
-        }
-
-        final float oldSize = getTextSize();
-        setTextSize(oldSize * mCompatScaling);
-        final float totalAdvance = nGetTextAdvances(mNativePaint, text, start, end, contextStart,
-                contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
-        setTextSize(oldSize);
-
-        if (advances != null) {
-            for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
-                advances[i] *= mInvCompatScaling;
-            }
-        }
-        return totalAdvance * mInvCompatScaling; // assume errors are insignificant
-    }
-
-    /**
      * Returns the next cursor position in the run.  This avoids placing the
      * cursor between surrogates, between characters that form conjuncts,
      * between base characters and combining marks, or within a reordering
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 5aa09ce..492c236 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -30,6 +30,7 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.net.Uri;
+import android.os.Build;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -1076,7 +1077,7 @@
     }
 
     // don't allow clients to call this directly
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private Typeface(long ni) {
         if (ni == 0) {
             throw new RuntimeException("native typeface cannot be made");
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 00380c5..11a46c4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -24,6 +24,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.LongSparseLongArray;
@@ -67,7 +68,7 @@
     private static final String ELEMENT_TRANSITION = "transition";
     private static final String ELEMENT_ITEM = "item";
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private AnimatedStateListState mState;
 
     /** The currently running transition, if any. */
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a337773..7efe522 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -34,6 +34,7 @@
 import android.graphics.PorterDuff;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Parcel;
@@ -101,7 +102,7 @@
 
     private static final int VERSION_STREAM_SERIALIZER = 1;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mType;
 
     private ColorStateList mTintList;
@@ -118,7 +119,7 @@
 
     // TYPE_RESOURCE: package name
     // TYPE_URI: uri string
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String          mString1;
 
     // TYPE_RESOURCE: resId
@@ -174,7 +175,7 @@
      * valid compressed bitmap data is found.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getDataOffset() {
         if (mType != TYPE_DATA) {
             throw new IllegalStateException("called getDataOffset() on " + this);
@@ -189,7 +190,7 @@
      * bitmap data.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public byte[] getDataBytes() {
         if (mType != TYPE_DATA) {
             throw new IllegalStateException("called getDataBytes() on " + this);
@@ -203,7 +204,7 @@
      * @return The {@link android.content.res.Resources} for this {@link #TYPE_RESOURCE} Icon.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public Resources getResources() {
         if (mType != TYPE_RESOURCE) {
             throw new IllegalStateException("called getResources() on " + this);
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 8aa4845..1458c66 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -119,7 +119,7 @@
 
         private @Nullable ByteBuffer mBuffer;
         private @Nullable File mFile;
-        private @NonNull LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
+        private @NonNull String mLocaleList = "";
         private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED;
         private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED;
         private @IntRange(from = 0) int mTtcIndex = 0;
@@ -150,7 +150,7 @@
          * @hide
          */
         public Builder(@NonNull ByteBuffer buffer, @NonNull File path,
-                @NonNull LocaleList localeList) {
+                @NonNull String localeList) {
             this(buffer);
             mFile = path;
             mLocaleList = localeList;
@@ -457,7 +457,7 @@
     private final boolean mItalic;
     private final @IntRange(from = 0) int mTtcIndex;
     private final @Nullable FontVariationAxis[] mAxes;
-    private final @NonNull LocaleList mLocaleList;
+    private final @NonNull String mLocaleList;
 
     /**
      * Use Builder instead
@@ -465,7 +465,7 @@
     private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
             @IntRange(from = 0, to = 1000) int weight, boolean italic,
             @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes,
-            @NonNull LocaleList localeList) {
+            @NonNull String localeList) {
         mBuffer = buffer;
         mFile = file;
         mWeight = weight;
@@ -546,7 +546,7 @@
      * @return a locale list
      */
     public @NonNull LocaleList getLocaleList() {
-        return mLocaleList;
+        return LocaleList.forLanguageTags(mLocaleList);
     }
 
     /** @hide */
@@ -580,7 +580,7 @@
             + ", italic=" + mItalic
             + ", ttcIndex=" + mTtcIndex
             + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
-            + ", localeList=" + mLocaleList.toLanguageTags()
+            + ", localeList=" + mLocaleList
             + ", buffer=" + mBuffer
             + "}";
     }
diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java
index 242cbb8..bcee559 100644
--- a/graphics/java/android/graphics/fonts/FontVariationAxis.java
+++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -29,7 +30,7 @@
  * Class that holds information about single font variation axis.
  */
 public final class FontVariationAxis {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final int mTag;
     private final String mTagString;
     @UnsupportedAppUsage
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 1c957b8..f4a2199 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
-import android.os.LocaleList;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -54,7 +53,7 @@
 
     private static final Map<String, FontFamily[]> sSystemFallbackMap;
     private static final FontConfig.Alias[] sAliases;
-    private static final Set<Font> sAvailableFonts;
+    private static final List<Font> sAvailableFonts;
 
     /**
      * Returns all available font files in the system.
@@ -63,7 +62,9 @@
      * @return an array of system fonts
      */
     public static @NonNull Set<Font> getAvailableFonts() {
-        return sAvailableFonts;
+        HashSet<Font> set = new HashSet<>();
+        set.addAll(sAvailableFonts);
+        return set;
     }
 
     /**
@@ -114,7 +115,7 @@
             @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
             @NonNull Map<String, ByteBuffer> cache,
             @NonNull String fontDir,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
 
         final String languageTags = xmlFamily.getLanguages();
         final int variant = xmlFamily.getVariant();
@@ -170,13 +171,12 @@
             @FontConfig.Family.Variant int variant,
             @NonNull Map<String, ByteBuffer> cache,
             @NonNull String fontDir,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
         if (fonts.size() == 0) {
             return null;
         }
 
         FontFamily.Builder b = null;
-        final LocaleList localeList = LocaleList.forLanguageTags(languageTags);
         for (int i = 0; i < fonts.size(); i++) {
             final FontConfig.Font fontConfig = fonts.get(i);
             final String fullPath = fontDir + fontConfig.getFontName();
@@ -194,7 +194,7 @@
 
             final Font font;
             try {
-                font = new Font.Builder(buffer, new File(fullPath), localeList)
+                font = new Font.Builder(buffer, new File(fullPath), languageTags)
                         .setWeight(fontConfig.getWeight())
                         .setItalic(fontConfig.isItalic())
                         .setTtcIndex(fontConfig.getTtcIndex())
@@ -228,7 +228,7 @@
     public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
             @NonNull String fontDir,
             @NonNull ArrayMap<String, FontFamily[]> fallbackMap,
-            @NonNull HashSet<Font> availableFonts) {
+            @NonNull ArrayList<Font> availableFonts) {
         try {
             final FileInputStream fontsIn = new FileInputStream(xmlPath);
             final FontConfig fontConfig = FontListParser.parse(fontsIn);
@@ -284,11 +284,11 @@
 
     static {
         final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
-        final HashSet<Font> availableFonts = new HashSet<>();
+        final ArrayList<Font> availableFonts = new ArrayList<>();
         sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
                 systemFallbackMap, availableFonts);
         sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
-        sAvailableFonts = Collections.unmodifiableSet(availableFonts);
+        sAvailableFonts = Collections.unmodifiableList(availableFonts);
     }
 
 }
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index d84a207..949c9445 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -60,7 +60,7 @@
   }
 
   T& editItemAt(size_t index) {
-    CHECK(index < size()) << "ByteBucketArray.getOrCreate(index=" << index
+    CHECK(index < size()) << "ByteBucketArray.editItemAt(index=" << index
                           << ") with size=" << size();
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 04bbe24..b011363 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -247,7 +247,7 @@
         // Enables fine-grained GLES error checking
         // If enabled, every GLES call is wrapped & error checked
         // Has moderate overhead
-        "hwui_enable_opengl_validation",
+        //"hwui_enable_opengl_validation",
     ],
 }
 
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index a43f58c..b5b87d5 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -66,12 +66,16 @@
         sDeviceInfo = new DeviceInfo();
         sDeviceInfo->mDisplayInfo = DeviceInfo::queryDisplayInfo();
         sDeviceInfo->mMaxTextureSize = maxTextureSize;
+        sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace,
+                                                &sDeviceInfo->mTargetPixelFormat);
     });
 }
 
 void DeviceInfo::load() {
     mDisplayInfo = queryDisplayInfo();
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+    sDeviceInfo->queryCompositionPreference(&sDeviceInfo->mTargetDataSpace,
+                                            &sDeviceInfo->mTargetPixelFormat);
 }
 
 DisplayInfo DeviceInfo::queryDisplayInfo() {
@@ -86,5 +90,17 @@
     return displayInfo;
 }
 
+void DeviceInfo::queryCompositionPreference(ui::Dataspace* dataSpace,
+                                            ui::PixelFormat* pixelFormat) {
+    if (Properties::isolatedProcess) {
+        *dataSpace = ui::Dataspace::V0_SRGB;
+        *pixelFormat = ui::PixelFormat::RGBA_8888;
+    }
+
+    status_t status =
+        SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 297b266..416af17 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -17,6 +17,7 @@
 #define DEVICEINFO_H
 
 #include <ui/DisplayInfo.h>
+#include <ui/GraphicTypes.h>
 
 #include "Extensions.h"
 #include "utils/Macros.h"
@@ -39,6 +40,8 @@
     static void initialize(int maxTextureSize);
 
     int maxTextureSize() const { return mMaxTextureSize; }
+    ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; }
+    ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; }
     const DisplayInfo& displayInfo() const { return mDisplayInfo; }
     const Extensions& extensions() const { return mExtensions; }
 
@@ -50,6 +53,9 @@
     static DisplayInfo queryDisplayInfo();
 
 private:
+    static void queryCompositionPreference(ui::Dataspace* dataSpace,
+                                           ui::PixelFormat* pixelFormat);
+
     DeviceInfo() {}
     ~DeviceInfo() {}
 
@@ -58,6 +64,9 @@
     int mMaxTextureSize;
     DisplayInfo mDisplayInfo;
     Extensions mExtensions;
+    // TODO(lpy) Replace below with android_ prefix types.
+    ui::Dataspace mTargetDataSpace;
+    ui::PixelFormat mTargetPixelFormat;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h
index b14b80c..6857999 100644
--- a/libs/hwui/LayerUpdateQueue.h
+++ b/libs/hwui/LayerUpdateQueue.h
@@ -19,6 +19,7 @@
 
 #include <utils/StrongPointer.h>
 #include "Rect.h"
+#include "RenderNode.h"
 #include "utils/Macros.h"
 
 #include <unordered_map>
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index d58b59e..3b1ebd6 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -27,6 +27,8 @@
 #include "utils/GLUtils.h"
 #include "utils/TraceUtils.h"
 
+#include <GLES3/gl3.h>
+
 #include <GrBackendSurface.h>
 #include <SkBlendMode.h>
 #include <SkImageInfo.h>
@@ -62,21 +64,23 @@
 bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                               const LightGeometry& lightGeometry,
                               LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                              bool opaque, bool wideColorGamut, const LightInfo& lightInfo,
+                              bool opaque, const LightInfo& lightInfo,
                               const std::vector<sp<RenderNode>>& renderNodes,
                               FrameInfoVisualizer* profiler) {
     mEglManager.damageFrame(frame, dirty);
 
-    SkColorType colorType;
+    SkColorType colorType = getSurfaceColorType();
     // setup surface for fbo0
     GrGLFramebufferInfo fboInfo;
     fboInfo.fFBOID = 0;
-    if (wideColorGamut) {
+    if (colorType == kRGBA_F16_SkColorType) {
         fboInfo.fFormat = GL_RGBA16F;
-        colorType = kRGBA_F16_SkColorType;
-    } else {
+    } else if (colorType == kN32_SkColorType) {
+        // Note: The default preference of pixel format is RGBA_8888, when other
+        // pixel format is available, we should branch out and do more check.
         fboInfo.fFormat = GL_RGBA8;
-        colorType = kN32_SkColorType;
+    } else {
+        LOG_ALWAYS_FATAL("Unsupported color type.");
     }
 
     GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo);
@@ -89,8 +93,7 @@
             nullptr, &props));
 
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
-                surface);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
@@ -147,8 +150,7 @@
 
     if (surface) {
         mRenderThread.requireGlContext();
-        const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
-        mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
+        mEglSurface = mEglManager.createSurface(surface, colorMode);
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
@@ -168,6 +170,14 @@
     return CC_LIKELY(mEglManager.hasEglContext());
 }
 
+SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const {
+    return mEglManager.getSurfaceColorType();
+}
+
+sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() {
+    return mEglManager.getSurfaceColorSpace();
+}
+
 void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
     if (thread.eglManager().hasEglContext()) {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 808685a..fbdf313 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -34,8 +34,7 @@
     renderthread::Frame getFrame() override;
     bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
               const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
-              const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
-              const LightInfo& lightInfo,
+              const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
@@ -46,6 +45,8 @@
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
+    SkColorType getSurfaceColorType() const override;
+    sk_sp<SkColorSpace> getSurfaceColorSpace() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 988981d..7f8abb8 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -83,16 +83,15 @@
 
 void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
                                 LayerUpdateQueue* layerUpdateQueue, bool opaque,
-                                bool wideColorGamut, const LightInfo& lightInfo) {
+                                const LightInfo& lightInfo) {
     updateLighting(lightGeometry, lightInfo);
     ATRACE_NAME("draw layers");
     renderVectorDrawableCache();
-    renderLayersImpl(*layerUpdateQueue, opaque, wideColorGamut);
+    renderLayersImpl(*layerUpdateQueue, opaque);
     layerUpdateQueue->clear();
 }
 
-void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
-                                    bool wideColorGamut) {
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
     sk_sp<GrContext> cachedContext;
 
     // Render all layers that need to be updated, in order.
@@ -161,7 +160,7 @@
 }
 
 bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                                       bool wideColorGamut, ErrorHandler* errorHandler) {
+                                       ErrorHandler* errorHandler) {
     // compute the size of the surface (i.e. texture) to be allocated for this layer
     const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE;
     const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE;
@@ -169,12 +168,8 @@
     SkSurface* layer = node->getLayerSurface();
     if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) {
         SkImageInfo info;
-        if (wideColorGamut) {
-            info = SkImageInfo::Make(surfaceWidth, surfaceHeight, kRGBA_F16_SkColorType,
-                                     kPremul_SkAlphaType);
-        } else {
-            info = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight);
-        }
+        info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(),
+                                 kPremul_SkAlphaType);
         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
         SkASSERT(mRenderThread.getGrContext() != nullptr);
         node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
@@ -321,19 +316,18 @@
 
 void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
                                const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                               bool wideColorGamut, const Rect& contentDrawBounds,
-                               sk_sp<SkSurface> surface) {
+                               const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
     renderVectorDrawableCache();
 
     // draw all layers up front
-    renderLayersImpl(layers, opaque, wideColorGamut);
+    renderLayersImpl(layers, opaque);
 
     // initialize the canvas for the current frame, that might be a recording canvas if SKP
     // capture is enabled.
     std::unique_ptr<SkPictureRecorder> recorder;
     SkCanvas* canvas = tryCapture(surface.get());
 
-    renderFrameImpl(layers, clip, nodes, opaque, wideColorGamut, contentDrawBounds, canvas);
+    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
 
     endCapture(surface.get());
 
@@ -354,13 +348,12 @@
 
 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                                   bool wideColorGamut, const Rect& contentDrawBounds,
-                                   SkCanvas* canvas) {
+                                   const Rect& contentDrawBounds, SkCanvas* canvas) {
     SkAutoCanvasRestore saver(canvas, true);
     canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
 
     // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
-    if (!opaque || wideColorGamut) {
+    if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) {
         canvas->clear(SK_ColorTRANSPARENT);
     }
 
@@ -493,7 +486,7 @@
     // each time a pixel would have been drawn.
     // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
     // initialized.
-    renderFrameImpl(layers, clip, nodes, true, false, contentDrawBounds, &overdrawCanvas);
+    renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
     sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
 
     // Draw overdraw colors to the canvas.  The color filter will convert counts to colors.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 8c9c803..b78dea1 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -42,15 +42,14 @@
     void unpinImages() override;
     void onPrepareTree() override;
 
-    void renderLayers(const LightGeometry& lightGeometry,
-                      LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
-                      const LightInfo& lightInfo) override;
+    void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+                      bool opaque, const LightInfo& lightInfo) override;
 
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                             bool wideColorGamut, ErrorHandler* errorHandler) override;
+                             ErrorHandler* errorHandler) override;
 
     void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
-                     const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+                     const std::vector<sp<RenderNode>>& nodes, bool opaque,
                      const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
 
     std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
@@ -59,7 +58,7 @@
 
     static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
 
-    void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, bool wideColorGamut);
+    void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
 
     static float getLightRadius() {
         if (CC_UNLIKELY(Properties::overrideLightRadius > 0)) {
@@ -112,7 +111,7 @@
 
 private:
     void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
-                         const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+                         const std::vector<sp<RenderNode>>& nodes, bool opaque,
                          const Rect& contentDrawBounds, SkCanvas* canvas);
 
     /**
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 611a34c..5cbe33d 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -63,8 +63,7 @@
 bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                               const LightGeometry& lightGeometry,
                               LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                              bool opaque, bool wideColorGamut,
-                              const LightInfo& lightInfo,
+                              bool opaque, const LightInfo& lightInfo,
                               const std::vector<sp<RenderNode>>& renderNodes,
                               FrameInfoVisualizer* profiler) {
     sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
@@ -72,8 +71,7 @@
         return false;
     }
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
-                backBuffer);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
@@ -139,6 +137,14 @@
     return CC_LIKELY(mVkManager.hasVkContext());
 }
 
+SkColorType SkiaVulkanPipeline::getSurfaceColorType() const {
+    return mVkManager.getSurfaceColorType();
+}
+
+sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() {
+    return mVkManager.getSurfaceColorSpace();
+}
+
 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
     // TODO: we currently don't support OpenGL WebView's
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 900b054..6e723a8 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -32,8 +32,7 @@
     renderthread::Frame getFrame() override;
     bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
               const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
-              const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
-              const LightInfo& lightInfo,
+              const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
@@ -44,6 +43,8 @@
     void onStop() override;
     bool isSurfaceReady() override;
     bool isContextReady() override;
+    SkColorType getSurfaceColorType() const override;
+    sk_sp<SkColorSpace> getSurfaceColorSpace() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
     static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 727cef3..ea6a851 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -151,7 +151,8 @@
 
     mNativeSurface = std::move(surface);
 
-    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb;
+    // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode.
+    ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy;
     bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
 
     mFrameNumber = -1;
@@ -416,7 +417,7 @@
     SkRect windowDirty = computeDirtyRect(frame, &dirty);
 
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
-                                      mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo,
+                                      mContentDrawBounds, mOpaque, mLightInfo,
                                       mRenderNodes, &(profiler()));
 
     int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1;
@@ -555,8 +556,7 @@
     // purposes when the frame is actually drawn
     node->setPropertyFieldsDirty(RenderNode::GENERIC);
 
-    mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut,
-                                  mLightInfo);
+    mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
 
     node->incStrong(nullptr);
     mPrefetchedLayers.insert(node);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 02ee72f..8448788 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -75,8 +75,7 @@
      */
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator,
                              ErrorHandler* errorHandler) {
-        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut,
-                errorHandler);
+        return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, errorHandler);
     }
 
     /**
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 5f8d7ad..675df41 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -20,6 +20,7 @@
 #include <log/log.h>
 #include <private/gui/SyncFeatures.h>
 #include <utils/Trace.h>
+#include "utils/Color.h"
 #include "utils/StringUtils.h"
 
 #include "DeviceInfo.h"
@@ -27,6 +28,7 @@
 #include "Properties.h"
 
 #include <EGL/eglext.h>
+#include <GLES/gl.h>
 
 #include <string>
 #include <vector>
@@ -75,6 +77,7 @@
     bool pixelFormatFloat = false;
     bool glColorSpace = false;
     bool scRGB = false;
+    bool displayP3 = false;
     bool contextPriority = false;
     bool surfacelessContext = false;
 } EglExtensions;
@@ -125,6 +128,17 @@
     createPBufferSurface();
     makeCurrent(mPBufferSurface, nullptr, /* force */ true);
     DeviceInfo::initialize();
+
+    mSurfaceColorGamut = DataSpaceToColorGamut(
+        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
+
+    LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut &&
+                        !EglExtensions.displayP3, "EGL doesn't support Display P3.");
+
+    mSurfaceColorType = PixelFormatToColorType(
+        static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat()));
+    mSurfaceColorSpace = DataSpaceToColorSpace(
+        static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace()));
 }
 
 void EglManager::initExtensions() {
@@ -148,6 +162,7 @@
 #else
     EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
 #endif
+    EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3");
     EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
     EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
 }
@@ -160,6 +175,10 @@
     ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
     EGLint swapBehavior =
             (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
+    // Note: The default pixel format is RGBA_8888, when other formats are
+    // available, we should check the target pixel format and configure the
+    // attributes list properly.
     EGLint attribs[] = {EGL_RENDERABLE_TYPE,
                         EGL_OPENGL_ES2_BIT,
                         EGL_RED_SIZE,
@@ -255,11 +274,12 @@
     }
 }
 
-EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
+EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode colorMode) {
     LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
 
-    wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
-                     EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+    bool wideColorGamut = colorMode == ColorMode::WideColorGamut && EglExtensions.glColorSpace &&
+                          EglExtensions.scRGB && EglExtensions.pixelFormatFloat &&
+                          EglExtensions.noConfigContext;
 
     // The color space we want to use depends on whether linear blending is turned
     // on and whether the app has requested wide color gamut rendering. When wide
@@ -269,9 +289,9 @@
     // When wide gamut rendering is off:
     // - Blending is done by default in gamma space, which requires using a
     //   linear EGL color space (the GPU uses the color values as is)
-    // - If linear blending is on, we must use the sRGB EGL color space (the
-    //   GPU will perform sRGB to linear and linear to SRGB conversions before
-    //   and after blending)
+    // - If linear blending is on, we must use the non-linear EGL color space
+    //   (the GPU will perform sRGB to linear and linear to SRGB conversions
+    //   before and after blending)
     //
     // When wide gamut rendering is on we cannot rely on the GPU performing
     // linear blending for us. We use two different color spaces to tag the
@@ -279,7 +299,7 @@
     // - Gamma blending (default) requires the use of the scRGB-nl color space
     // - Linear blending requires the use of the scRGB color space
 
-    // Not all Android targets support the EGL_GL_COLOR_SPACE_KHR extension
+    // Not all Android targets support the EGL_GL_COLORSPACE_KHR extension
     // We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
     // According to section 3.4.1 of the EGL specification, the attributes
     // list is considered empty if the first entry is EGL_NONE
@@ -291,13 +311,21 @@
         if (wideColorGamut) {
             attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
         } else {
-            attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
+            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
+                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
+            } else {
+                attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
+            }
         }
 #else
         if (wideColorGamut) {
             attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
         } else {
-            attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+            if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) {
+                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT;
+            } else {
+                attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+            }
         }
 #endif
     }
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 507673a..e97228c 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -18,11 +18,13 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <SkImageInfo.h>
 #include <SkRect.h>
 #include <cutils/compiler.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
+#include "IRenderPipeline.h"
 
 namespace android {
 namespace uirenderer {
@@ -45,7 +47,7 @@
 
     bool hasEglContext();
 
-    EGLSurface createSurface(EGLNativeWindowType window, bool wideColorGamut);
+    EGLSurface createSurface(EGLNativeWindowType window, ColorMode colorMode);
     void destroySurface(EGLSurface surface);
 
     void destroy();
@@ -76,6 +78,9 @@
     // Depending on installed extensions, the result is either Android native fence or EGL fence.
     status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
 
+    SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+    sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; }
+
 private:
 
     void initExtensions();
@@ -89,8 +94,10 @@
     EGLConfig mEglConfigWideGamut;
     EGLContext mEglContext;
     EGLSurface mPBufferSurface;
-
     EGLSurface mCurrentSurface;
+    SkColorSpace::Gamut mSurfaceColorGamut;
+    SkColorType mSurfaceColorType;
+    sk_sp<SkColorSpace> mSurfaceColorSpace;
 
     enum class SwapBehavior {
         Discard,
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index b7b7853..0297c9c 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -16,11 +16,12 @@
 
 #pragma once
 
+#include "DamageAccumulator.h"
 #include "FrameInfoVisualizer.h"
 #include "LayerUpdateQueue.h"
+#include "Lighting.h"
 #include "SwapBehavior.h"
 #include "hwui/Bitmap.h"
-#include "thread/TaskManager.h"
 
 #include <SkRect.h>
 #include <utils/RefBase.h>
@@ -35,13 +36,25 @@
 
 class DeferredLayerUpdater;
 class ErrorHandler;
+class TaskManager;
 
 namespace renderthread {
 
 enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
 
 enum class ColorMode {
-    Srgb,
+    // Legacy means HWUI will produce buffer with whatever platform prefers
+    // HWUI to produce, however, HWUI doesn't accurately convert color from
+    // source color space to destination color space, instead HWUI will take
+    // the pixel value directly and interpret it destination color space.
+    Legacy,
+    // DisplayColorGamut means HWUI will produce buffer with whatever platform
+    // prefers HWUI to produce and accurately convert color from source color
+    // space to destination color space.
+    DisplayColorGamut,
+    // WideColorGamut means HWUI would support rendering scRGB non-linear into
+    // a signed buffer with enough range to support the wide color gamut of the
+    // display.
     WideColorGamut,
     // Hdr
 };
@@ -55,7 +68,7 @@
     virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                       const LightGeometry& lightGeometry,
                       LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                      bool opaque, bool wideColorGamut, const LightInfo& lightInfo,
+                      bool opaque, const LightInfo& lightInfo,
                       const std::vector<sp<RenderNode>>& renderNodes,
                       FrameInfoVisualizer* profiler) = 0;
     virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
@@ -67,15 +80,17 @@
     virtual bool isContextReady() = 0;
     virtual void onDestroyHardwareResources() = 0;
     virtual void renderLayers(const LightGeometry& lightGeometry,
-                              LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+                              LayerUpdateQueue* layerUpdateQueue, bool opaque,
                               const LightInfo& lightInfo) = 0;
     virtual TaskManager* getTaskManager() = 0;
     virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
-                                     bool wideColorGamut, ErrorHandler* errorHandler) = 0;
+                                     ErrorHandler* errorHandler) = 0;
     virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
     virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
     virtual void unpinImages() = 0;
     virtual void onPrepareTree() = 0;
+    virtual SkColorType getSurfaceColorType() const = 0;
+    virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index ebc11a5..7a539ae 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -118,6 +118,10 @@
     // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
     status_t createReleaseFence(sp<Fence>& nativeFence);
 
+    // TODO(b/115636873): Handle composition preference.
+    SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; }
+    sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); }
+
 private:
     friend class RenderThread;
 
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 48bc8e4..2926ef3 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -537,7 +537,7 @@
     layerUpdateQueue.enqueueLayerWithDamage(child.get(),
                                             android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    pipeline->renderLayersImpl(layerUpdateQueue, true, false);
+    pipeline->renderLayersImpl(layerUpdateQueue, true);
     EXPECT_EQ(1, drawCounter);  // assert index 0 is drawn on the layer
 
     RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index a9124d9..5e5d134 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -50,7 +50,7 @@
     auto surface = SkSurface::MakeRasterN32Premul(1, 1);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
@@ -83,7 +83,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
     // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
@@ -105,11 +105,11 @@
     auto surface = SkSurface::MakeRasterN32Premul(2, 2);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
@@ -129,7 +129,7 @@
     auto surface = SkSurface::MakeRasterN32Premul(2, 2);
     surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
@@ -171,7 +171,7 @@
     lightGeometry.center = {0.0f, 0.0f, 0.0f};
     LightInfo lightInfo;
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo);
+    pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE);
@@ -202,37 +202,37 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
     // Single draw, should be white.
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
 
     // 1 Overdraw, should be blue blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff);
 
     // 2 Overdraw, should be green blended onto white
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0);
 
     // 3 Overdraw, should be pink blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0);
 
     // 4 Overdraw, should be red blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
 
     // 5 Overdraw, should be red blended onto white.
     renderNodes.push_back(whiteNode);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
                           surface);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
 }
@@ -318,7 +318,7 @@
     SkRect dirty = SkRect::MakeWH(800, 600);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
     EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
@@ -348,7 +348,7 @@
     SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
                           SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
@@ -378,7 +378,7 @@
     SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
-    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
                           SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index a3e7859..d35fe4f 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -57,6 +57,45 @@
     return false;
 }
 
+SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) {
+    switch (pixelFormat) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+            return SkColorType::kN32_SkColorType;
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+            return SkColorType::kRGBA_F16_SkColorType;
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+            return SkColorType::kRGBA_1010102_SkColorType;
+        default:
+            ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat);
+            return SkColorType::kN32_SkColorType;
+    }
+}
+
+SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) {
+    switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            return SkColorSpace::kSRGB_Gamut;
+        case HAL_DATASPACE_STANDARD_BT2020:
+            return SkColorSpace::kRec2020_Gamut;
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            return SkColorSpace::kDCIP3_D65_Gamut;
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            return SkColorSpace::kAdobeRGB_Gamut;
+        case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+        case HAL_DATASPACE_STANDARD_BT601_625:
+        case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT601_525:
+        case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+        case HAL_DATASPACE_STANDARD_BT470M:
+        case HAL_DATASPACE_STANDARD_FILM:
+        default:
+            ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace);
+            return SkColorSpace::kSRGB_Gamut;
+    }
+}
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
     SkColorSpace::Gamut gamut;
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 3c13a54..ff0e755 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -21,6 +21,7 @@
 
 #include <SkColor.h>
 #include <SkColorSpace.h>
+#include <SkImageInfo.h>
 
 namespace android {
 namespace uirenderer {
@@ -113,6 +114,10 @@
 // returns true for sRGB, gamma 2.2 and Display P3 for instance
 bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
 
+SkColorType PixelFormatToColorType(android_pixel_format pixelFormat);
+
+SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace);
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
 
 struct Lab {
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index 119d1e0..ae13949 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -21,6 +21,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -88,7 +89,7 @@
      *       create an instance of this class is using the factory
      *       Context.getSystemService.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public CountryDetector(ICountryDetector service) {
         mService = service;
         mListeners = new HashMap<CountryListener, ListenerTransport>();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 5ad7365..f1325ce 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -375,11 +376,11 @@
 
     @UnsupportedAppUsage
     private int mUsage = USAGE_UNKNOWN;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mContentType = CONTENT_TYPE_UNKNOWN;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mFlags = 0x0;
     private HashSet<String> mTags;
     @UnsupportedAppUsage
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index aaf7dd7..62e58ca 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1656,7 +1656,7 @@
     * @param timestamp a reference to a non-null AudioTimestamp instance allocated
     *        and owned by caller.
     * @return true if a timestamp is available, or false if no timestamp is available.
-    *         If a timestamp if available,
+    *         If a timestamp is available,
     *         the AudioTimestamp instance is filled in with a position in frame units, together
     *         with the estimated time when that frame was presented or is committed to
     *         be presented.
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d45acdf..d1d605f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.media.MediaCodecInfo.CodecCapabilities;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -3580,7 +3581,7 @@
         native_init();
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private long mNativeContext;
 
     /** @hide */
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index ef312d1..995ebb2 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -1589,7 +1590,7 @@
         private VideoCapabilities() { }
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public static VideoCapabilities create(
                 MediaFormat info, CodecCapabilities parent) {
             VideoCapabilities caps = new VideoCapabilities();
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 43bee85..ffeff4d 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -34,6 +34,7 @@
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.session.MediaSession;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -2064,7 +2065,7 @@
         }
 
         /** @hide */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public boolean isDefault() {
             return this == sStatic.mDefaultAudioVideo;
         }
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 716e0cb..f704acd 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -18,9 +18,12 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.util.Log;
 
+import dalvik.system.VMRuntime;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
@@ -42,7 +45,10 @@
  *
  * @hide This file is shared between MediaStore and MediaProvider and should remained internal use
  *       only.
+ * @deprecated thumbnails are now maintained in separate files, and this file
+ *             format is no longer used.
  */
+@Deprecated
 public class MiniThumbFile {
     private static final String TAG = "MiniThumbFile";
     private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
@@ -69,6 +75,9 @@
     }
 
     public static synchronized MiniThumbFile instance(Uri uri) {
+        if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
+            throw new UnsupportedOperationException();
+        }
         String type = uri.getPathSegments().get(1);
         MiniThumbFile file = sThumbFiles.get(type);
         // Log.v(TAG, "get minithumbfile for type: "+type);
diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java
index 6594dd7..3fe1a32 100644
--- a/media/java/android/media/PlaybackParams.java
+++ b/media/java/android/media/PlaybackParams.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -94,7 +95,7 @@
     private static final int SET_AUDIO_FALLBACK_MODE = 1 << 2;
     @UnsupportedAppUsage
     private static final int SET_AUDIO_STRETCH_MODE  = 1 << 3;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mSet = 0;
 
     // params
@@ -104,7 +105,7 @@
     private int mAudioStretchMode = AUDIO_STRETCH_MODE_DEFAULT;
     @UnsupportedAppUsage
     private float mPitch = 1.0f;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private float mSpeed = 1.0f;
 
     public PlaybackParams() {
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 1a456f6..9746842 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -872,7 +873,7 @@
      * In case of failure, the returned value is negative and implementation specific.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int command(int cmdCode, byte[] command, byte[] reply)
             throws IllegalStateException {
         checkState("command()");
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 43847cc..24d003b 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,6 +49,7 @@
         "sharedmem.cpp",
         "storage_manager.cpp",
         "surface_texture.cpp",
+        "system_fonts.cpp",
         "trace.cpp",
     ],
 
@@ -65,6 +66,7 @@
         "libandroid_runtime",
         "libnetd_client",
         "libhwui",
+        "libxml2",
     ],
 
     static_libs: [
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index ac5ded6..9f48bc9 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -212,6 +212,18 @@
     ASurfaceTexture_getTransformMatrix; # introduced=28
     ASurfaceTexture_release; # introduced=28
     ASurfaceTexture_updateTexImage; # introduced=28
+    ASystemFontIterator_open; # introduced=29
+    ASystemFontIterator_close; # introduced=29
+    ASystemFontIterator_next; # introduced=29
+    ASystemFont_close; # introduced=29
+    ASystemFont_getFontFilePath; # introduced=29
+    ASystemFont_getWeight; # introduced=29
+    ASystemFont_isItalic; # introduced=29
+    ASystemFont_getLocale; # introduced=29
+    ASystemFont_getCollectionIndex; # introduced=29
+    ASystemFont_getAxisCount; # introduced=29
+    ASystemFont_getAxisTag; # introduced=29
+    ASystemFont_getAxisValue; # introduced=29
     ATrace_beginSection; # introduced=23
     ATrace_endSection; # introduced=23
     ATrace_isEnabled; # introduced=23
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
new file mode 100644
index 0000000..b95adad
--- /dev/null
+++ b/native/android/system_fonts.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+
+#include <android/system_fonts.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libxml/tree.h>
+#include <log/log.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+struct XmlCharDeleter {
+    void operator()(xmlChar* b) { xmlFree(b); }
+};
+
+struct XmlDocDeleter {
+    void operator()(xmlDoc* d) { xmlFreeDoc(d); }
+};
+
+using XmlCharUniquePtr = std::unique_ptr<xmlChar, XmlCharDeleter>;
+using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>;
+
+struct ASystemFontIterator {
+    XmlDocUniquePtr mXmlDoc;
+    xmlNode* mFontNode;
+};
+
+struct ASystemFont {
+    std::string mFilePath;
+    std::unique_ptr<std::string> mLocale;
+    uint16_t mWeight;
+    bool mItalic;
+    uint32_t mCollectionIndex;
+    std::vector<std::pair<uint32_t, float>> mAxes;
+};
+
+namespace {
+
+std::string xmlTrim(const std::string& in) {
+    if (in.empty()) {
+        return in;
+    }
+    const char XML_SPACES[] = "\u0020\u000D\u000A\u0009";
+    const size_t start = in.find_first_not_of(XML_SPACES);  // inclusive
+    if (start == std::string::npos) {
+        return "";
+    }
+    const size_t end = in.find_last_not_of(XML_SPACES);     // inclusive
+    if (end == std::string::npos) {
+        return "";
+    }
+    return in.substr(start, end - start + 1 /* +1 since end is inclusive */);
+}
+
+const xmlChar* FAMILY_TAG = BAD_CAST("family");
+const xmlChar* FONT_TAG = BAD_CAST("font");
+
+xmlNode* firstElement(xmlNode* node, const xmlChar* tag) {
+    for (xmlNode* child = node->children; child; child = child->next) {
+        if (xmlStrEqual(child->name, tag)) {
+            return child;
+        }
+    }
+    return nullptr;
+}
+
+xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) {
+    while ((node = node->next) != nullptr) {
+        if (xmlStrEqual(node->name, tag)) {
+            return node;
+        }
+    }
+    return nullptr;
+}
+
+void copyFont(ASystemFontIterator* ite, ASystemFont* out) {
+    const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
+    XmlCharUniquePtr filePathStr(
+            xmlNodeListGetString(ite->mXmlDoc.get(), ite->mFontNode->xmlChildrenNode, 1));
+    out->mFilePath = "/system/fonts/" + xmlTrim(
+            std::string(filePathStr.get(), filePathStr.get() + xmlStrlen(filePathStr.get())));
+
+    const xmlChar* WEIGHT_ATTR_NAME = BAD_CAST("weight");
+    XmlCharUniquePtr weightStr(xmlGetProp(ite->mFontNode, WEIGHT_ATTR_NAME));
+    out->mWeight = weightStr ?
+            strtol(reinterpret_cast<const char*>(weightStr.get()), nullptr, 10) : 400;
+
+    const xmlChar* STYLE_ATTR_NAME = BAD_CAST("style");
+    const xmlChar* ITALIC_ATTR_VALUE = BAD_CAST("italic");
+    XmlCharUniquePtr styleStr(xmlGetProp(ite->mFontNode, STYLE_ATTR_NAME));
+    out->mItalic = styleStr ? xmlStrEqual(styleStr.get(), ITALIC_ATTR_VALUE) : false;
+
+    const xmlChar* INDEX_ATTR_NAME = BAD_CAST("index");
+    XmlCharUniquePtr indexStr(xmlGetProp(ite->mFontNode, INDEX_ATTR_NAME));
+    out->mCollectionIndex =  indexStr ?
+            strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0;
+
+    XmlCharUniquePtr localeStr(xmlGetProp(ite->mXmlDoc->parent, LOCALE_ATTR_NAME));
+    out->mLocale.reset(
+            localeStr ? new std::string(reinterpret_cast<const char*>(localeStr.get())) : nullptr);
+
+    const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag");
+    const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue");
+    const xmlChar* AXIS_TAG = BAD_CAST("axis");
+    out->mAxes.clear();
+    for (xmlNode* axis = firstElement(ite->mFontNode, AXIS_TAG); axis;
+            axis = nextSibling(axis, AXIS_TAG)) {
+        XmlCharUniquePtr tagStr(xmlGetProp(axis, TAG_ATTR_NAME));
+        if (!tagStr || xmlStrlen(tagStr.get()) != 4) {
+            continue;  // Tag value must be 4 char string
+        }
+
+        XmlCharUniquePtr styleValueStr(xmlGetProp(axis, STYLEVALUE_ATTR_NAME));
+        if (!styleValueStr) {
+            continue;
+        }
+
+        uint32_t tag =
+            static_cast<uint32_t>(tagStr.get()[0] << 24) |
+            static_cast<uint32_t>(tagStr.get()[1] << 16) |
+            static_cast<uint32_t>(tagStr.get()[2] << 8) |
+            static_cast<uint32_t>(tagStr.get()[3]);
+        float styleValue = strtod(reinterpret_cast<const char*>(styleValueStr.get()), nullptr);
+        out->mAxes.push_back(std::make_pair(tag, styleValue));
+    }
+}
+
+bool isFontFileAvailable(const std::string& filePath) {
+    std::string fullPath = filePath;
+    struct stat st = {};
+    if (stat(fullPath.c_str(), &st) != 0) {
+        return false;
+    }
+    return S_ISREG(st.st_mode);
+}
+
+xmlNode* findFirstFontNode(xmlDoc* doc) {
+    xmlNode* familySet = xmlDocGetRootElement(doc);
+    if (familySet == nullptr) {
+        return nullptr;
+    }
+    xmlNode* family = firstElement(familySet, FAMILY_TAG);
+    if (family == nullptr) {
+        return nullptr;
+    }
+
+    xmlNode* font = firstElement(family, FONT_TAG);
+    while (font == nullptr) {
+        family = nextSibling(family, FAMILY_TAG);
+        if (family == nullptr) {
+            return nullptr;
+        }
+        font = firstElement(family, FONT_TAG);
+    }
+    return font;
+}
+
+}  // namespace
+
+ASystemFontIterator* ASystemFontIterator_open() {
+    std::unique_ptr<ASystemFontIterator> ite(new ASystemFontIterator());
+    ite->mXmlDoc.reset(xmlReadFile("/system/etc/fonts.xml", nullptr, 0));
+    return ite.release();
+}
+
+void ASystemFontIterator_close(ASystemFontIterator* ite) {
+    delete ite;
+}
+
+ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
+    LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument");
+    if (ite->mFontNode == nullptr) {
+        if (ite->mXmlDoc == nullptr) {
+            return nullptr;  // Already at the end.
+        } else {
+            // First time to query font.
+            ite->mFontNode = findFirstFontNode(ite->mXmlDoc.get());
+            if (ite->mFontNode == nullptr) {
+                ite->mXmlDoc.reset();
+                return nullptr;  // No font node found.
+            }
+            std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+            copyFont(ite, font.get());
+            return font.release();
+        }
+    } else {
+        xmlNode* nextNode = nextSibling(ite->mFontNode, FONT_TAG);
+        while (nextNode == nullptr) {
+            xmlNode* family = nextSibling(ite->mFontNode->parent, FAMILY_TAG);
+            if (family == nullptr) {
+                break;
+            }
+            nextNode = firstElement(family, FONT_TAG);
+        }
+        ite->mFontNode = nextNode;
+        if (nextNode == nullptr) {
+            ite->mXmlDoc.reset();
+            return nullptr;
+        }
+
+        std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+        copyFont(ite, font.get());
+        if (!isFontFileAvailable(font->mFilePath)) {
+            // fonts.xml intentionally contains missing font configuration. Skip it.
+            return ASystemFontIterator_next(ite);
+        }
+        return font.release();
+    }
+}
+
+void ASystemFont_close(ASystemFont* font) {
+    delete font;
+}
+
+const char* ASystemFont_getFontFilePath(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mFilePath.c_str();
+}
+
+uint16_t ASystemFont_getWeight(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mWeight;
+}
+
+bool ASystemFont_isItalic(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
+    return font->mItalic;
+}
+
+const char* ASystemFont_getLocale(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mLocale ? nullptr : font->mLocale->c_str();
+}
+
+size_t ASystemFont_getCollectionIndex(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mCollectionIndex;
+}
+
+size_t ASystemFont_getAxisCount(const ASystemFont* font) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    return font->mAxes.size();
+}
+
+uint32_t ASystemFont_getAxisTag(const ASystemFont* font, uint32_t axisIndex) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
+                        "given axis index is out of bounds. (< %zd", font->mAxes.size());
+    return font->mAxes[axisIndex].first;
+}
+
+float ASystemFont_getAxisValue(const ASystemFont* font, uint32_t axisIndex) {
+    LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
+    LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
+                        "given axis index is out of bounds. (< %zd", font->mAxes.size());
+    return font->mAxes[axisIndex].second;
+}
diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp
index adb371d..7f71f63 100644
--- a/native/webview/loader/loader.cpp
+++ b/native/webview/loader/loader.cpp
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -58,13 +59,15 @@
           vsize, strerror(errno));
     return JNI_FALSE;
   }
+  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, vsize, "libwebview reservation");
   gReservedAddress = addr;
   gReservedSize = vsize;
   ALOGV("Reserved %zd bytes at %p", vsize, addr);
   return JNI_TRUE;
 }
 
-jboolean DoCreateRelroFile(const char* lib, const char* relro) {
+jboolean DoCreateRelroFile(JNIEnv* env, const char* lib, const char* relro,
+                           jobject clazzLoader) {
   // Try to unlink the old file, since if this is being called, the old one is
   // obsolete.
   if (unlink(relro) != 0 && errno != ENOENT) {
@@ -82,11 +85,19 @@
     ALOGE("Failed to create temporary file %s: %s", relro_tmp, strerror(errno));
     return JNI_FALSE;
   }
+  android_namespace_t* ns =
+      android::FindNamespaceByClassLoader(env, clazzLoader);
+  if (ns == NULL) {
+    ALOGE("Failed to find classloader namespace");
+    return JNI_FALSE;
+  }
   android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO;
+  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO |
+                  ANDROID_DLEXT_USE_NAMESPACE;
   extinfo.reserved_addr = gReservedAddress;
   extinfo.reserved_size = gReservedSize;
   extinfo.relro_fd = tmp_fd;
+  extinfo.library_namespace = ns;
   void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo);
   int close_result = close(tmp_fd);
   if (handle == NULL) {
@@ -143,13 +154,14 @@
   return DoReserveAddressSpace(size);
 }
 
-jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro) {
+jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro,
+                         jobject clazzLoader) {
   jboolean ret = JNI_FALSE;
   const char* lib_utf8 = env->GetStringUTFChars(lib, NULL);
   if (lib_utf8 != NULL) {
     const char* relro_utf8 = env->GetStringUTFChars(relro, NULL);
     if (relro_utf8 != NULL) {
-      ret = DoCreateRelroFile(lib_utf8, relro_utf8);
+      ret = DoCreateRelroFile(env, lib_utf8, relro_utf8, clazzLoader);
       env->ReleaseStringUTFChars(relro, relro_utf8);
     }
     env->ReleaseStringUTFChars(lib, lib_utf8);
@@ -179,7 +191,7 @@
   { "nativeReserveAddressSpace", "(J)Z",
       reinterpret_cast<void*>(ReserveAddressSpace) },
   { "nativeCreateRelroFile",
-      "(Ljava/lang/String;Ljava/lang/String;)Z",
+      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)Z",
       reinterpret_cast<void*>(CreateRelroFile) },
   { "nativeLoadWithRelroFile",
       "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)I",
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
index 6473f0d..0467bff 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
@@ -177,7 +177,7 @@
                             }
                         }
                         textView.getViewTreeObserver().removeOnPreDrawListener(this);
-                        return false;
+                        return true;
                     }
                 });
         textView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/packages/CarrierDefaultApp/Android.mk b/packages/CarrierDefaultApp/Android.mk
index 5068b3b..df88afd 100644
--- a/packages/CarrierDefaultApp/Android.mk
+++ b/packages/CarrierDefaultApp/Android.mk
@@ -9,8 +9,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
-LOCAL_STATIC_JAVA_LIBRARIES := services.net
-
 include $(BUILD_PACKAGE)
 
 # This finds and builds the test apk as well, so a single make does both.
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index b1933373..4f67350 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -32,7 +32,6 @@
 import android.net.Proxy;
 import android.net.TrafficStats;
 import android.net.Uri;
-import android.net.dns.ResolvUtil;
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.telephony.CarrierConfigManager;
@@ -159,9 +158,9 @@
 
     private void setNetwork(Network network) {
         if (network != null) {
+            network = network.getPrivateDnsBypassingCopy();
             mCm.bindProcessToNetwork(network);
-            mCm.setProcessDefaultNetworkForHostResolution(
-                    ResolvUtil.getNetworkWithUseLocalNameserversFlag(network));
+            mCm.setProcessDefaultNetworkForHostResolution(network);
         }
         mNetwork = network;
     }
@@ -242,7 +241,6 @@
     private void testForCaptivePortal() {
         mTestingThread = new Thread(new Runnable() {
             public void run() {
-                final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork);
                 // Give time for captive portal to open.
                 try {
                     Thread.sleep(1000);
@@ -253,7 +251,7 @@
                 int httpResponseCode = 500;
                 int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
                 try {
-                    urlConnection = (HttpURLConnection) network.openConnection(
+                    urlConnection = (HttpURLConnection) mNetwork.openConnection(
                             new URL(mCm.getCaptivePortalServerUrl()));
                     urlConnection.setInstanceFollowRedirects(false);
                     urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ab2892f..d29bd65 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -135,7 +135,7 @@
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"테더링"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"테더링 및 휴대용 핫스팟"</string>
     <string name="managed_user_title" msgid="8109605045406748842">"모든 직장 앱"</string>
-    <string name="user_guest" msgid="8475274842845401871">"손님"</string>
+    <string name="user_guest" msgid="8475274842845401871">"게스트"</string>
     <string name="unknown" msgid="1592123443519355854">"알 수 없음"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"사용자: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="313159469856372621">"일부 기본값이 설정됨"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
index 3bade25..192a40c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java
@@ -26,6 +26,12 @@
 import androidx.preference.DialogPreference;
 import androidx.preference.PreferenceDialogFragment;
 
+/**
+ * Framework version is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class CustomDialogPreference extends DialogPreference {
 
     private CustomPreferenceDialogFragment mFragment;
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
index dfaff61..3caa0bb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -31,6 +31,12 @@
 import androidx.preference.EditTextPreference;
 import androidx.preference.EditTextPreferenceDialogFragment;
 
+/**
+ * Framework version is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class CustomEditTextPreference extends EditTextPreference {
 
     private CustomPreferenceDialogFragment mFragment;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
index 223c055..60d22a0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoader.java
@@ -34,8 +34,11 @@
 import com.android.settingslib.AppItem;
 
 /**
- * Loader for historical chart data for both network and UID details.
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
  */
+@Deprecated
 public class ChartDataLoader extends AsyncTaskLoader<ChartData> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_APP = "app";
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
index 572bae1..649aeff 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
@@ -24,6 +24,12 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 
+/**
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class SummaryForAllUidLoader extends AsyncTaskLoader<NetworkStats> {
     private static final String KEY_TEMPLATE = "template";
     private static final String KEY_START = "start";
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
index 6597daa..b0e987e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java
@@ -32,8 +32,11 @@
 import java.util.List;
 
 /**
- * Manages IPC communication to SettingsIntelligence for suggestion related services.
+ * Framework mixin is deprecated, use the compat version instead.
+ *
+ * @deprecated
  */
+@Deprecated
 public class SuggestionControllerMixin implements SuggestionController.ServiceConnectionListener,
         androidx.lifecycle.LifecycleObserver, LoaderManager.LoaderCallbacks<List<Suggestion>> {
 
@@ -65,7 +68,7 @@
         mContext = context.getApplicationContext();
         mHost = host;
         mSuggestionController = new SuggestionController(mContext, componentName,
-                    this /* serviceConnectionListener */);
+                this /* serviceConnectionListener */);
         if (lifecycle != null) {
             lifecycle.addObserver(this);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
index 9c1af1e..8011424 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoader.java
@@ -24,6 +24,12 @@
 
 import java.util.List;
 
+/**
+ * Framework loader is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class SuggestionLoader extends AsyncLoader<List<Suggestion>> {
 
     public static final int LOADER_ID_SUGGESTIONS = 42;
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
index 06770ac..64b9ffe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoader.java
@@ -29,7 +29,9 @@
  * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo.
  *
  * @param <T> the data type to be loaded.
+ * @deprecated Framework loader is deprecated, use the compat version instead.
  */
+@Deprecated
 public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> {
     private T mResult;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
index 2987c15..fcf2363 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java
@@ -25,6 +25,12 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen;
 
+/**
+ * Framework mixin is deprecated, use the compat version instead.
+ *
+ * @deprecated
+ */
+@Deprecated
 public class FooterPreferenceMixin implements LifecycleObserver, SetPreferenceScreen {
 
     private final PreferenceFragment mFragment;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index c6ea480..bd21b83 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1617,6 +1617,12 @@
         dumpSetting(s, p,
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                 SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
+                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_MS);
         p.end(accessibilityToken);
 
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 290a4f8..63978ba 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2948,7 +2948,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 171;
+            private static final int SETTINGS_VERSION = 172;
 
             private final int mUserId;
 
@@ -3900,6 +3900,37 @@
                     currentVersion = 171;
                 }
 
+                if (currentVersion == 171) {
+                    // Version 171: by default, add STREAM_VOICE_CALL to list of streams that can
+                    // be muted.
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    final Setting currentSetting = systemSettings.getSettingLocked(
+                              Settings.System.MUTE_STREAMS_AFFECTED);
+                    if (!currentSetting.isNull()) {
+                        try {
+                            int currentSettingIntegerValue = Integer.parseInt(
+                                    currentSetting.getValue());
+                            if ((currentSettingIntegerValue
+                                 & (1 << AudioManager.STREAM_VOICE_CALL)) == 0) {
+                                systemSettings.insertSettingLocked(
+                                    Settings.System.MUTE_STREAMS_AFFECTED,
+                                    Integer.toString(
+                                        currentSettingIntegerValue
+                                        | (1 << AudioManager.STREAM_VOICE_CALL)),
+                                    null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                            }
+                        } catch (NumberFormatException e) {
+                            // remove the setting in case it is not a valid integer
+                            Slog.w("Failed to parse integer value of MUTE_STREAMS_AFFECTED"
+                                   + "setting, removing setting", e);
+                            systemSettings.deleteSettingLocked(
+                                Settings.System.MUTE_STREAMS_AFFECTED);
+                        }
+
+                    }
+                    currentVersion = 172;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index b6f51bc..95569dc 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -613,7 +613,7 @@
             final String name, final String value, final int userId) throws Exception {
         ContentResolver contentResolver = getContext().getContentResolver();
 
-        final Uri settingUri = getBaseUriForType(type);
+        final Uri settingUri = getBaseUriForType(type).buildUpon().appendPath(name).build();
 
         final AtomicBoolean success = new AtomicBoolean();
 
@@ -640,20 +640,22 @@
 
             final long startTimeMillis = SystemClock.uptimeMillis();
             synchronized (mLock) {
-                if (success.get()) {
-                    return;
-                }
-                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
-                if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
-                    fail("Could not change setting for "
-                            + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
-                }
-                final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
-                        - elapsedTimeMillis;
-                try {
-                    mLock.wait(remainingTimeMillis);
-                } catch (InterruptedException ie) {
-                    /* ignore */
+                while (true) {
+                    if (success.get()) {
+                        return;
+                    }
+                    final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                    if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+                        fail("Could not change setting for "
+                                + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
+                    }
+                    final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
+                            - elapsedTimeMillis;
+                    try {
+                        mLock.wait(remainingTimeMillis);
+                    } catch (InterruptedException ie) {
+                        /* ignore */
+                    }
                 }
             }
         } finally {
@@ -689,39 +691,50 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_enableProviders() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationModeChanges_viaFrontEndApi() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
                 UserHandle.USER_SYSTEM);
-
-        // Enable one provider
-        updateStringViaProviderApiSetting(
-                SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+gps");
-
         assertEquals(
                 "Wrong location providers",
-                "gps",
-                queryStringViaProviderApi(
-                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+                "",
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
 
-        // Enable a list of providers, including the one that is already enabled
-        updateStringViaProviderApiSetting(
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
-                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "+gps,+network,+network");
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_BATTERY_SAVING),
+                UserHandle.USER_SYSTEM);
+        assertEquals(
+                "Wrong location providers",
+                "network",
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
 
+        setStringViaFrontEndApiSetting(
+                SETTING_TYPE_SECURE,
+                Settings.Secure.LOCATION_MODE,
+                String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
+                UserHandle.USER_SYSTEM);
         assertEquals(
                 "Wrong location providers",
                 "gps,network",
-                queryStringViaProviderApi(
-                        SETTING_TYPE_SECURE, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+                getStringViaFrontEndApiSetting(
+                        SETTING_TYPE_SECURE,
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        UserHandle.USER_SYSTEM));
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_disableProviders() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowed_disableProviders() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY),
@@ -732,7 +745,6 @@
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 "-gps,-network");
-
         assertEquals(
                 "Wrong location providers",
                 "",
@@ -744,7 +756,6 @@
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 "-test");
-
         assertEquals(
                 "Wrong location providers",
                 "",
@@ -753,8 +764,8 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_enableAndDisable() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowed_enableAndDisable() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
@@ -775,8 +786,8 @@
     }
 
     @Test
-    public void testUpdateLocationProvidersAllowedLocked_invalidInput() throws Exception {
-        setSettingViaFrontEndApiAndAssertSuccessfulChange(
+    public void testLocationProvidersAllowedLocked_invalidInput() throws Exception {
+        setStringViaFrontEndApiSetting(
                 SETTING_TYPE_SECURE,
                 Settings.Secure.LOCATION_MODE,
                 String.valueOf(Settings.Secure.LOCATION_MODE_OFF),
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
index 0734e0d..4fbc226 100644
--- a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -20,6 +20,7 @@
 import android.database.MatrixCursor;
 import android.database.MatrixCursor.RowBuilder;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
@@ -68,6 +69,18 @@
     }
 
     @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final Cursor c = super.queryChildDocuments(parentDocumentId, projection, sortOrder);
+        final Bundle extras = new Bundle();
+        extras.putCharSequence(DocumentsContract.EXTRA_INFO,
+                getContext().getText(R.string.bugreport_confirm));
+        c.setExtras(extras);
+        return c;
+    }
+
+    @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
         if (DOC_ID_ROOT.equals(documentId)) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e31dd1e..3725940 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -216,6 +216,7 @@
 
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
+    <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
 
     <application
         android:name=".SystemUIApplication"
diff --git a/packages/SystemUI/res/layout/operator_name.xml b/packages/SystemUI/res/layout/operator_name.xml
index c4f75e9..015e30a 100644
--- a/packages/SystemUI/res/layout/operator_name.xml
+++ b/packages/SystemUI/res/layout/operator_name.xml
@@ -27,5 +27,6 @@
         android:maxLength="20"
         android:gravity="center_vertical|start"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:singleLine="true" />
+        android:singleLine="true"
+        android:paddingEnd="5dp" />
 </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 45d2185..2c5120d 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -25,10 +25,10 @@
     <color name="notification_legacy_background_color">@*android:color/notification_material_background_color</color>
 
     <!-- The color of the material notification background when dimmed -->
-    <color name="notification_material_background_dimmed_color">#aa212121</color>
+    <color name="notification_material_background_dimmed_color">#aa000000</color>
 
     <!-- The color of the dividing line between grouped notifications while . -->
-    <color name="notification_divider_color">#000</color>
+    <color name="notification_divider_color">#212121</color>
 
     <!-- The background color of the notification shade -->
     <color name="notification_shade_background_color">#181818</color>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 67db68d..216ed68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1141,9 +1141,13 @@
     }
 
     private void updateNotificationColor() {
+        Configuration currentConfig = getResources().getConfiguration();
+        boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+
         mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
                 getStatusBarNotification().getNotification().color,
-                getBackgroundColorWithoutTint());
+                getBackgroundColorWithoutTint(), nightMode);
         mNotificationColorAmbient = ContrastColorUtil.resolveAmbientColor(mContext,
                 getStatusBarNotification().getNotification().color);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 5fe362f..6b6566c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -415,10 +415,10 @@
             return false;
         }
         NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null) {
+        if (group == null || group.summary == null) {
             return false;
         }
-        return !group.children.isEmpty();
+        return !group.children.isEmpty() && Objects.equals(group.summary.notification, sbn);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7ec4db2..7316c02dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -732,10 +732,12 @@
 
         IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
                 Context.VR_SERVICE));
-        try {
-            vrManager.registerListener(mVrStateCallbacks);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+        if (vrManager != null) {
+            try {
+                vrManager.registerListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            }
         }
 
         IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
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 3c16329..e9efaa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -205,6 +205,8 @@
         public void onTetheringFailed() {
             if (DEBUG) Log.d(TAG, "onTetheringFailed");
             mWaitingForCallback = false;
+            // TODO(b/110697252): stopTethering must be called to reset soft ap state after failure
+            mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
             fireHotspotChangedCallback(isHotspotEnabled());
           // TODO: Show error.
         }
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 8b1324a..e73c70b 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:sharedUserId="android.uid.system"
     package="com.android.systemui.tests">
 
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
new file mode 100644
index 0000000..6a3c8a8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationGroupManagerTest extends SysuiTestCase {
+    @Rule
+    public MockitoRule rule = MockitoJUnit.rule();
+
+    private static final String TEST_CHANNEL_ID = "test_channel";
+    private static final String TEST_GROUP_ID = "test_group";
+    private static final String TEST_PACKAGE_NAME = "test_pkg";
+    private NotificationGroupManager mGroupManager = new NotificationGroupManager();
+    private int mId = 0;
+
+    @Mock HeadsUpManager mHeadsUpManager;
+
+    @Before
+    public void setup() {
+         mGroupManager.setHeadsUpManager(mHeadsUpManager);
+         mGroupManager.setOnGroupChangeListener(mock(OnGroupChangeListener.class));
+    }
+
+    @Test
+    public void testIsOnlyChildInGroup() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        assertTrue(mGroupManager.isOnlyChildInGroup(childEntry.notification));
+    }
+
+    @Test
+    public void testIsChildInGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        assertTrue(mGroupManager.isChildInGroupWithSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testIsSummaryOfGroupWithChildren() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        assertTrue(mGroupManager.isSummaryOfGroup(summaryEntry.notification));
+        assertEquals(summaryEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testRemoveChildFromGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        mGroupManager.onEntryRemoved(childEntry);
+
+        assertFalse(mGroupManager.isChildInGroupWithSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testRemoveSummaryFromGroupWithSummary() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+
+        mGroupManager.onEntryRemoved(summaryEntry);
+
+        assertNull(mGroupManager.getGroupSummary(childEntry.notification));
+        assertFalse(mGroupManager.isSummaryOfGroup(summaryEntry.notification));
+    }
+
+    @Test
+    public void testHeadsUpEntryIsIsolated() {
+        NotificationData.Entry childEntry = createChildNotification();
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        mGroupManager.onEntryAdded(createChildNotification());
+        when(childEntry.row.isHeadsUp()).thenReturn(true);
+        when(mHeadsUpManager.contains(childEntry.key)).thenReturn(true);
+
+        mGroupManager.onHeadsUpStateChanged(childEntry, true);
+
+        // Child entries that are heads upped should be considered separate groups visually even if
+        // they are the same group logically
+        assertEquals(childEntry.row, mGroupManager.getGroupSummary(childEntry.notification));
+        assertEquals(summaryEntry.row,
+                mGroupManager.getLogicalGroupSummary(childEntry.notification));
+    }
+
+    @Test
+    public void testSuppressedSummaryHeadsUpTransfersToChild() {
+        NotificationData.Entry summaryEntry = createSummaryNotification();
+        when(summaryEntry.row.isHeadsUp()).thenReturn(true);
+        when(mHeadsUpManager.contains(summaryEntry.key)).thenReturn(true);
+        NotificationData.Entry childEntry = createChildNotification();
+
+        // Summary will be suppressed because there is only one child
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // A suppressed summary should transfer its heads up state to the child
+        verify(mHeadsUpManager, never()).showNotification(summaryEntry);
+        verify(mHeadsUpManager).showNotification(childEntry);
+    }
+
+    @Test
+    public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
+        mHeadsUpManager = new HeadsUpManager(mContext) {};
+        mGroupManager.setHeadsUpManager(mHeadsUpManager);
+        NotificationData.Entry summaryEntry =
+                createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
+        when(summaryEntry.row.isHeadsUp()).thenReturn(true);
+        NotificationData.Entry childEntry =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        NotificationData.Entry childEntry2 =
+                createChildNotification(Notification.GROUP_ALERT_SUMMARY);
+        // Trigger a transfer of heads up state from summary to child.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+        when(summaryEntry.row.isHeadsUp()).thenReturn(false);
+        when(childEntry.row.isHeadsUp()).thenReturn(true);
+
+        // Add second child notification so that summary is no longer suppressed.
+        mGroupManager.onEntryAdded(childEntry2);
+
+        // The heads up state should transfer back to the summary as there is now more than one
+        // child and the summary should no longer be suppressed.
+        assertTrue(mHeadsUpManager.contains(summaryEntry.key));
+        assertFalse(mHeadsUpManager.contains(childEntry.key));
+    }
+
+    private NotificationData.Entry createSummaryNotification() {
+        return createSummaryNotification(Notification.GROUP_ALERT_ALL);
+    }
+
+    private NotificationData.Entry createSummaryNotification(int groupAlertBehavior) {
+        return createEntry(true, groupAlertBehavior);
+    }
+
+    private NotificationData.Entry createChildNotification() {
+        return createChildNotification(Notification.GROUP_ALERT_ALL);
+    }
+
+    private NotificationData.Entry createChildNotification(int groupAlertBehavior) {
+        return createEntry(false, groupAlertBehavior);
+    }
+
+    private NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) {
+        Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+                .setContentTitle("Title")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupAlertBehavior(groupAlertBehavior)
+                .setGroupSummary(isSummary)
+                .setGroup(TEST_GROUP_ID)
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(
+                TEST_PACKAGE_NAME /* pkg */,
+                TEST_PACKAGE_NAME,
+                mId++,
+                null /* tag */,
+                0, /* uid */
+                0 /* initialPid */,
+                notif,
+                new UserHandle(ActivityManager.getCurrentUser()),
+                null /* overrideGroupKey */,
+                0 /* postTime */);
+        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        entry.row = row;
+        when(row.getEntry()).thenReturn(entry);
+        when(row.getStatusBarNotification()).thenReturn(sbn);
+        return entry;
+    }
+}
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index 3732ebc..21cfc04 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que permite controlar el tráfico de la red. Acéptala solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando la VPN está activa."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de controlar el tráfico de la red. Acéptala solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando se activa la VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"La VPN está conectada."</string>
     <string name="session" msgid="6470628549473641030">"Sesión:"</string>
     <string name="duration" msgid="3584782459928719435">"Duración:"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b2e06f9..9bee8db 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -21,6 +21,8 @@
 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
@@ -1689,6 +1691,24 @@
                 this, userState));
     }
 
+    private void scheduleSetAllClientsMinimumUiTimeout(UserState userState) {
+        mMainHandler.sendMessage(obtainMessage(
+                AccessibilityManagerService::sendMinimumUiTimeoutChanged,
+                this, userState.mUserClients, userState.mMinimumUiTimeout));
+    }
+
+    private void sendMinimumUiTimeoutChanged(
+            RemoteCallbackList<IAccessibilityManagerClient> userClients, int uiTimeout) {
+        notifyClientsOfServicesMinimumUiTimeoutChange(mGlobalClients, uiTimeout);
+        notifyClientsOfServicesMinimumUiTimeoutChange(userClients, uiTimeout);
+    }
+
+    private void notifyClientsOfServicesMinimumUiTimeoutChange(
+            RemoteCallbackList<IAccessibilityManagerClient> clients, int uiTimeout) {
+        clients.broadcast(ignoreRemoteException(
+                client -> client.setMinimumUiTimeout(uiTimeout)));
+    }
+
     private void updateInputFilter(UserState userState) {
         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
 
@@ -1822,6 +1842,7 @@
         scheduleUpdateClientsIfNeededLocked(userState);
         updateRelevantEventsLocked(userState);
         updateAccessibilityButtonTargetsLocked(userState);
+        updateMinimumUiTimeoutLocked(userState);
     }
 
     private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -1940,6 +1961,7 @@
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
         somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
+        somethingChanged |= readUserMinimumUiTimeoutSettingsLocked(userState);
         return somethingChanged;
     }
 
@@ -2084,6 +2106,22 @@
         return true;
     }
 
+    private boolean readUserMinimumUiTimeoutSettingsLocked(UserState userState) {
+        final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, 0,
+                userState.mUserId) == 1;
+        final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, 0,
+                userState.mUserId);
+        if (enabled != userState.mUserMinimumUiTimeoutEnabled
+                || timeout != userState.mUserMinimumUiTimeout) {
+            userState.mUserMinimumUiTimeoutEnabled = enabled;
+            userState.mUserMinimumUiTimeout = timeout;
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Check if the service that will be enabled by the shortcut is installed. If it isn't,
      * clear the value and the associated setting so a sideloaded service can't spoof the
@@ -2250,6 +2288,27 @@
         }
     }
 
+    private void updateMinimumUiTimeoutLocked(UserState userState) {
+        int newUiTimeout = 0;
+        if (userState.mUserMinimumUiTimeoutEnabled) {
+            newUiTimeout = userState.mUserMinimumUiTimeout;
+        } else {
+            final List<AccessibilityServiceConnection> services = userState.mBoundServices;
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                final int serviceUiTimeout = services.get(i).getServiceInfo()
+                        .getMinimumUiTimeoutMillis();
+                if (newUiTimeout < serviceUiTimeout) {
+                    newUiTimeout = serviceUiTimeout;
+                }
+            }
+        }
+        if (newUiTimeout != userState.mMinimumUiTimeout) {
+            userState.mMinimumUiTimeout = newUiTimeout;
+            scheduleSetAllClientsMinimumUiTimeout(userState);
+        }
+    }
+
     @GuardedBy("mLock")
     @Override
     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
@@ -2388,6 +2447,20 @@
         return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
     }
 
+    /**
+     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+     * on the screen for at least this long to give users time to react.
+     *
+     * @return The minimum timeout for the current user in milliseconds.
+     */
+    @Override
+    public int getMinimumUiTimeout() {
+        synchronized(mLock) {
+            final UserState userState = getCurrentUserStateLocked();
+            return userState.mMinimumUiTimeout;
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -2405,6 +2478,7 @@
                 pw.append(", navBarMagnificationEnabled="
                         + userState.mIsNavBarMagnificationEnabled);
                 pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
+                pw.append(", minimumUiTimeout=" + userState.mMinimumUiTimeout);
                 if (mUiAutomationManager.isUiAutomationRunningLocked()) {
                     pw.append(", ");
                     mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
@@ -2549,6 +2623,38 @@
         return -1;
     }
 
+    private void notifyOutsideTouchIfNeeded(int targetWindowId, int action, Bundle arguments,
+            int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
+            int interrogatingPid, long interrogatingTid) {
+        if (action != ACTION_CLICK && action != ACTION_LONG_CLICK) {
+            return;
+        }
+
+        final List<Integer> outsideWindowsIds;
+        final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
+        synchronized (mLock) {
+            outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowId(targetWindowId);
+            for (int i = 0; i < outsideWindowsIds.size(); i++) {
+                connectionList.add(getConnectionLocked(outsideWindowsIds.get(i)));
+            }
+        }
+        for (int i = 0; i < connectionList.size(); i++) {
+            final RemoteAccessibilityConnection connection = connectionList.get(i);
+            if (connection != null) {
+                try {
+                    connection.mConnection.performAccessibilityAction(
+                            AccessibilityNodeInfo.ROOT_ITEM_ID,
+                            R.id.accessibilityActionOutsideTouch, arguments, interactionId,
+                            callback, fetchFlags, interrogatingPid, interrogatingTid);
+                } catch (RemoteException re) {
+                    if (DEBUG) {
+                        Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void ensureWindowsAvailableTimed() {
         synchronized (mLock) {
@@ -2628,6 +2734,8 @@
             mPowerManager.userActivity(SystemClock.uptimeMillis(),
                     PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
 
+            notifyOutsideTouchIfNeeded(resolvedWindowId, action, arguments, interactionId, callback,
+                    fetchFlags, interrogatingPid, interrogatingTid);
             if (activityToken != null) {
                 LocalServices.getService(ActivityTaskManagerInternal.class)
                         .setFocusedActivity(activityToken);
@@ -2955,6 +3063,7 @@
         public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
         private boolean mTouchInteractionInProgress;
+        private boolean mHasWatchOutsideTouchWindow;
 
         private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) {
             final int eventType = event.getEventType();
@@ -3112,6 +3221,7 @@
                 mWindowInfoById.valueAt(i).recycle();
             }
             mWindowInfoById.clear();
+            mHasWatchOutsideTouchWindow = false;
 
             mFocusedWindowId = INVALID_WINDOW_ID;
             if (!mTouchInteractionInProgress) {
@@ -3156,6 +3266,9 @@
                                 activeWindowGone = false;
                             }
                         }
+                        if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) {
+                            mHasWatchOutsideTouchWindow = true;
+                        }
                         mWindows.add(window);
                         mA11yWindowInfoById.put(windowId, window);
                         mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo));
@@ -3574,6 +3687,22 @@
             return mWindowInfoById.get(windowId);
         }
 
+        private List<Integer> getWatchOutsideTouchWindowId(int targetWindowId) {
+            if (mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
+                final List<Integer> outsideWindowsId = new ArrayList<>();
+                final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
+                for (int i = 0; i < mWindowInfoById.size(); i++) {
+                    WindowInfo window = mWindowInfoById.valueAt(i);
+                    if (window.layer < targetWindow.layer
+                            && window.hasFlagWatchOutsideTouch) {
+                        outsideWindowsId.add(mWindowInfoById.keyAt(i));
+                    }
+                }
+                return outsideWindowsId;
+            }
+            return Collections.emptyList();
+        }
+
         private AccessibilityWindowInfo getPictureInPictureWindow() {
             if (mWindows != null) {
                 final int windowCount = mWindows.size();
@@ -3660,6 +3789,7 @@
         public ComponentName mServiceToEnableWithShortcut;
 
         public int mLastSentClientState = -1;
+        public int mMinimumUiTimeout = 0;
 
         private int mSoftKeyboardShowMode = 0;
 
@@ -3674,6 +3804,8 @@
         public boolean mIsPerformGesturesEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mAccessibilityFocusOnlyInActiveWindow;
+        public boolean mUserMinimumUiTimeoutEnabled;
+        public int mUserMinimumUiTimeout;
 
         public boolean mBindInstantServiceAllowed;
 
@@ -3713,6 +3845,9 @@
             // Clear event management state.
             mLastSentClientState = -1;
 
+            // clear minimum ui timeout
+            mMinimumUiTimeout = 0;
+
             // Clear state persisted in settings.
             mEnabledServices.clear();
             mTouchExplorationGrantedServices.clear();
@@ -3722,6 +3857,8 @@
             mServiceAssignedToAccessibilityButton = null;
             mIsNavBarMagnificationAssignedToAccessibilityButton = false;
             mIsAutoclickEnabled = false;
+            mUserMinimumUiTimeoutEnabled = false;
+            mUserMinimumUiTimeout = 0;
         }
 
         public void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -3948,6 +4085,12 @@
         private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
 
+        private final Uri mUserMinimumUiTimeoutEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED);
+
+        private final Uri mUserMinimumUiTimeoutUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -3982,6 +4125,10 @@
                     mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mUserMinimumUiTimeoutEnabledUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mUserMinimumUiTimeoutUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4032,6 +4179,11 @@
                     if (readAccessibilityButtonSettingsLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
+                } else if (mUserMinimumUiTimeoutEnabledUri.equals(uri)
+                        || mUserMinimumUiTimeoutUri.equals(uri)) {
+                    if (readUserMinimumUiTimeoutSettingsLocked(userState)) {
+                        updateMinimumUiTimeoutLocked(userState);
+                    }
                 }
             }
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 371f932..cf9f233 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -170,6 +170,20 @@
      *                action.
      */
     public TouchExplorer(Context context, AccessibilityManagerService service) {
+        this(context, service, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context A context handle for accessing resources.
+     * @param service The service to notify touch interaction and gesture completed and to perform
+     *                action.
+     * @param detector The gesture detector to handle accessibility touch event. If null the default
+     *                one created in place, or for testing purpose.
+     */
+    public TouchExplorer(Context context, AccessibilityManagerService service,
+            AccessibilityGestureDetector detector) {
         mContext = context;
         mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -186,7 +200,11 @@
         mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                 mDetermineUserIntentTimeout);
-        mGestureDetector = new AccessibilityGestureDetector(context, this);
+        if (detector == null) {
+            mGestureDetector = new AccessibilityGestureDetector(context, this);
+        } else {
+            mGestureDetector = detector;
+        }
         final float density = context.getResources().getDisplayMetrics().density;
         mScaledMinPointerDistanceToUseMiddleLocation =
             (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c26ac17..1b97926 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -698,8 +698,6 @@
     @GuardedBy("mQueueLock")
     private ArrayList<FullBackupEntry> mFullBackupQueue;
 
-    private BackupPolicyEnforcer mBackupPolicyEnforcer;
-
     // Utility: build a new random integer token. The low bits are the ordinal of the
     // operation for near-time uniqueness, and the upper bits are random for app-
     // side unpredictability.
@@ -899,8 +897,6 @@
 
         // Power management
         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
-
-        mBackupPolicyEnforcer = new BackupPolicyEnforcer(context);
     }
 
     private void initPackageTracking() {
@@ -2827,10 +2823,6 @@
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
-        if (!enable && mBackupPolicyEnforcer.getMandatoryBackupTransport() != null) {
-            Slog.w(TAG, "Cannot disable backups when the mandatory backups policy is active.");
-            return;
-        }
 
         Slog.i(TAG, "Backup enabled => " + enable);
 
@@ -3085,12 +3077,6 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "selectBackupTransport");
 
-        if (!isAllowedByMandatoryBackupTransportPolicy(transportName)) {
-            // Don't change the transport if it is not allowed.
-            Slog.w(TAG, "Failed to select transport - disallowed by device owner policy.");
-            return mTransportManager.getCurrentTransportName();
-        }
-
         final long oldId = Binder.clearCallingIdentity();
         try {
             String previousTransportName = mTransportManager.selectTransport(transportName);
@@ -3105,20 +3091,10 @@
 
     @Override
     public void selectBackupTransportAsync(
-            ComponentName transportComponent, @Nullable ISelectBackupTransportCallback listener) {
+            ComponentName transportComponent, ISelectBackupTransportCallback listener) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "selectBackupTransportAsync");
-        if (!isAllowedByMandatoryBackupTransportPolicy(transportComponent)) {
-            try {
-                if (listener != null) {
-                    Slog.w(TAG, "Failed to select transport - disallowed by device owner policy.");
-                    listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "ISelectBackupTransportCallback listener not available");
-            }
-            return;
-        }
+
         final long oldId = Binder.clearCallingIdentity();
         try {
             String transportString = transportComponent.flattenToShortString();
@@ -3140,12 +3116,10 @@
                         }
 
                         try {
-                            if (listener != null) {
-                                if (transportName != null) {
-                                    listener.onSuccess(transportName);
-                                } else {
-                                    listener.onFailure(result);
-                                }
+                            if (transportName != null) {
+                                listener.onSuccess(transportName);
+                            } else {
+                                listener.onFailure(result);
                             }
                         } catch (RemoteException e) {
                             Slog.e(TAG, "ISelectBackupTransportCallback listener not available");
@@ -3156,38 +3130,6 @@
         }
     }
 
-    /**
-     * Returns if the specified transport can be set as the current transport without violating the
-     * mandatory backup transport policy.
-     */
-    private boolean isAllowedByMandatoryBackupTransportPolicy(String transportName) {
-        ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport();
-        if (mandatoryBackupTransport == null) {
-            return true;
-        }
-        final String mandatoryBackupTransportName;
-        try {
-            mandatoryBackupTransportName =
-                    mTransportManager.getTransportName(mandatoryBackupTransport);
-        } catch (TransportNotRegisteredException e) {
-            Slog.e(TAG, "mandatory backup transport not registered!");
-            return false;
-        }
-        return TextUtils.equals(mandatoryBackupTransportName, transportName);
-    }
-
-    /**
-     * Returns if the specified transport can be set as the current transport without violating the
-     * mandatory backup transport policy.
-     */
-    private boolean isAllowedByMandatoryBackupTransportPolicy(ComponentName transport) {
-        ComponentName mandatoryBackupTransport = mBackupPolicyEnforcer.getMandatoryBackupTransport();
-        if (mandatoryBackupTransport == null) {
-            return true;
-        }
-        return mandatoryBackupTransport.equals(transport);
-    }
-
     private void updateStateForTransport(String newTransportName) {
         // Publish the name change
         Settings.Secure.putString(mContext.getContentResolver(),
diff --git a/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java b/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java
deleted file mode 100644
index 158084a..0000000
--- a/services/backup/java/com/android/server/backup/BackupPolicyEnforcer.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.android.server.backup;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * A helper class to decouple this service from {@link DevicePolicyManager} in order to improve
- * testability.
- */
-@VisibleForTesting
-public class BackupPolicyEnforcer {
-    private DevicePolicyManager mDevicePolicyManager;
-
-    public BackupPolicyEnforcer(Context context) {
-        mDevicePolicyManager =
-                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
-    }
-
-    public ComponentName getMandatoryBackupTransport() {
-        return mDevicePolicyManager.getMandatoryBackupTransport();
-    }
-}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 499c03d..ad2f82c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -81,6 +81,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseLongArray;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -3637,6 +3638,8 @@
                         if (DEBUG_BATCH) {
                             Slog.v(TAG, "Time changed notification from kernel; rebatching");
                         }
+                        // StatsLog requires currentTimeMillis(), which == nowRTC to within usecs.
+                        StatsLog.write(StatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC);
                         removeImpl(mTimeTickSender);
                         removeImpl(mDateChangeSender);
                         rebatchAllAlarms();
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 15673a7..51d95a2 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -118,10 +118,22 @@
             this.mBinderCallsStats = binderCallsStats;
         }
 
+        /** @see BinderCallsStats#reset */
+        public void reset() {
+            mBinderCallsStats.reset();
+        }
+
+        /**
+         * @see BinderCallsStats#getExportedCallStats.
+         *
+         * Note that binder calls stats will be reset by statsd every time
+         * the data is exported.
+         */
         public ArrayList<BinderCallsStats.ExportedCallStat> getExportedCallStats() {
             return mBinderCallsStats.getExportedCallStats();
         }
 
+        /** @see BinderCallsStats#getExportedExceptionStats */
         public ArrayMap<String, Integer> getExportedExceptionStats() {
             return mBinderCallsStats.getExportedExceptionStats();
         }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 01e8152..380f6a7 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -612,7 +612,7 @@
                 mSrvConfig
                         .getNetdInstance()
                         .ipSecDeleteSecurityAssociation(
-                                mResourceId,
+                                uid,
                                 mConfig.getSourceAddress(),
                                 mConfig.getDestinationAddress(),
                                 spi,
@@ -679,7 +679,7 @@
                     mSrvConfig
                             .getNetdInstance()
                             .ipSecDeleteSecurityAssociation(
-                                    mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                                    uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
@@ -821,13 +821,13 @@
 
                 for (int selAddrFamily : ADDRESS_FAMILIES) {
                     netd.ipSecDeleteSecurityPolicy(
-                            0,
+                            uid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_OUT,
                             mOkey,
                             0xffffffff);
                     netd.ipSecDeleteSecurityPolicy(
-                            0,
+                            uid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_IN,
                             mIkey,
@@ -1083,7 +1083,8 @@
         }
         checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
         final int resourceId = mNextResourceId++;
 
         int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
@@ -1096,7 +1097,7 @@
             spi =
                     mSrvConfig
                             .getNetdInstance()
-                            .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi);
+                            .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
             Log.d(TAG, "Allocated SPI " + spi);
             userRecord.mSpiRecords.put(
                     resourceId,
@@ -1264,7 +1265,8 @@
         // TODO: Check that underlying network exists, and IP addresses not assigned to a different
         //       network (b/72316676).
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callerUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid);
         if (!userRecord.mTunnelQuotaTracker.isAvailable()) {
             return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
         }
@@ -1285,7 +1287,7 @@
             for (int selAddrFamily : ADDRESS_FAMILIES) {
                 // Always send down correct local/remote addresses for template.
                 netd.ipSecAddSecurityPolicy(
-                        0, // Use 0 for reqId
+                        callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_OUT,
                         localAddr,
@@ -1294,7 +1296,7 @@
                         okey,
                         0xffffffff);
                 netd.ipSecAddSecurityPolicy(
-                        0, // Use 0 for reqId
+                        callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_IN,
                         remoteAddr,
@@ -1532,7 +1534,7 @@
         mSrvConfig
                 .getNetdInstance()
                 .ipSecAddSecurityAssociation(
-                        resourceId,
+                        Binder.getCallingUid(),
                         c.getMode(),
                         c.getSourceAddress(),
                         c.getDestinationAddress(),
@@ -1623,13 +1625,14 @@
     @Override
     public synchronized void applyTransportModeTransform(
             ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
         checkDirection(direction);
         // Get transform record; if no transform is found, will throw IllegalArgumentException
         TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
 
         // TODO: make this a function.
-        if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
+        if (info.pid != getCallingPid() || info.uid != callingUid) {
             throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
         }
 
@@ -1643,7 +1646,7 @@
                 .getNetdInstance()
                 .ipSecApplyTransportModeTransform(
                         socket.getFileDescriptor(),
-                        resourceId,
+                        callingUid,
                         direction,
                         c.getSourceAddress(),
                         c.getDestinationAddress(),
@@ -1675,7 +1678,8 @@
         enforceTunnelPermissions(callingPackage);
         checkDirection(direction);
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
 
         // Get transform record; if no transform is found, will throw IllegalArgumentException
         TransformRecord transformInfo =
@@ -1717,7 +1721,7 @@
                     mSrvConfig
                             .getNetdInstance()
                             .ipSecUpdateSecurityPolicy(
-                                    0, // Use 0 for reqId
+                                    callingUid,
                                     selAddrFamily,
                                     direction,
                                     tunnelInterfaceInfo.getLocalAddress(),
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index daf870d..1d163ee 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1565,10 +1565,11 @@
 
             try {
                 // TODO: support quota shared across interfaces
-                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
+                mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
+
                 mActiveQuotas.put(iface, quotaBytes);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
 
             synchronized (mTetheringStatsProviders) {
@@ -1599,9 +1600,9 @@
 
             try {
                 // TODO: support quota shared across interfaces
-                mConnector.execute("bandwidth", "removeiquota", iface);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+                mNetdService.bandwidthRemoveInterfaceQuota(iface);
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
 
             synchronized (mTetheringStatsProviders) {
@@ -1633,10 +1634,10 @@
 
             try {
                 // TODO: support alert shared across interfaces
-                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
+                mNetdService.bandwidthSetInterfaceAlert(iface, alertBytes);
                 mActiveAlerts.put(iface, alertBytes);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
         }
     }
@@ -1653,10 +1654,10 @@
 
             try {
                 // TODO: support alert shared across interfaces
-                mConnector.execute("bandwidth", "removeinterfacealert", iface);
+                mNetdService.bandwidthRemoveInterfaceAlert(iface);
                 mActiveAlerts.remove(iface);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
         }
     }
@@ -1666,18 +1667,15 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.bandwidthSetGlobalAlert(alertBytes);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
     private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final String chain = blacklist ? "naughtyapps" : "niceapps";
-        final String suffix = enable ? "add" : "remove";
-
         synchronized (mQuotaLock) {
             boolean oldEnable;
             SparseBooleanArray quotaList;
@@ -1692,7 +1690,19 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
             try {
-                mConnector.execute("bandwidth", suffix + chain, uid);
+                if (blacklist) {
+                    if (enable) {
+                        mNetdService.bandwidthAddNaughtyApp(uid);
+                    } else {
+                        mNetdService.bandwidthRemoveNaughtyApp(uid);
+                    }
+                } else {
+                    if (enable) {
+                        mNetdService.bandwidthAddNiceApp(uid);
+                    } else {
+                        mNetdService.bandwidthRemoveNiceApp(uid);
+                    }
+                }
                 synchronized (mRulesLock) {
                     if (enable) {
                         quotaList.put(uid, true);
@@ -1700,8 +1710,8 @@
                         quotaList.delete(uid);
                     }
                 }
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2c8f2fc..3a0289c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -68,6 +68,7 @@
     static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry";
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
+    static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -97,6 +98,7 @@
     private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16;
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
+    private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -212,6 +214,10 @@
     // throttle requests from apps.
     public long MEMORY_INFO_THROTTLE_TIME = DEFAULT_MEMORY_INFO_THROTTLE_TIME;
 
+    // Allow app just moving from TOP to FOREGROUND_SERVICE to stay in a higher adj value for
+    // this long.
+    public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
+
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     boolean mFlagActivityStartsLoggingEnabled;
@@ -355,6 +361,8 @@
                     DEFAULT_PROCESS_START_ASYNC);
             MEMORY_INFO_THROTTLE_TIME = mParser.getLong(KEY_MEMORY_INFO_THROTTLE_TIME,
                     DEFAULT_MEMORY_INFO_THROTTLE_TIME);
+            TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
+                    DEFAULT_TOP_TO_FGS_GRACE_DURATION);
 
             updateMaxCachedProcesses();
         }
@@ -438,6 +446,8 @@
         pw.println(FLAG_PROCESS_START_ASYNC);
         pw.print("  "); pw.print(KEY_MEMORY_INFO_THROTTLE_TIME); pw.print("=");
         pw.println(MEMORY_INFO_THROTTLE_TIME);
+        pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
+        pw.println(TOP_TO_FGS_GRACE_DURATION);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b64e8b8..7533db1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17778,6 +17778,19 @@
             }
         }
 
+        // If the app was recently in the foreground and moved to a foreground service status,
+        // allow it to get a higher rank in memory for some time, compared to other foreground
+        // services so that it can finish performing any persistence/processing of in-memory state.
+        if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
+                && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
+                    || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) {
+            adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+            app.adjType = "fg-service-act";
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
+            }
+        }
+
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                 || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
             if (app.forcingToImportant != null) {
@@ -18045,6 +18058,10 @@
                                         cr.trackProcState(procState, mAdjSeq, now);
                                         trackedProcState = true;
                                     }
+                                } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0
+                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) {
+                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1;
                                 } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                         && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                         && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -19044,6 +19061,8 @@
             // Must be called before updating setProcState
             maybeUpdateUsageStatsLocked(app, nowElapsed);
 
+            maybeUpdateLastTopTime(app, now);
+
             app.setProcState = app.curProcState;
             if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                 app.notCachedSinceIdle = false;
@@ -19268,6 +19287,13 @@
         }
     }
 
+    private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
+        if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
+                && app.curProcState > ActivityManager.PROCESS_STATE_TOP) {
+            app.lastTopTime = nowUptime;
+        }
+    }
+
     private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
         if (proc.thread != null && proc.baseProcessTracker != null) {
             proc.baseProcessTracker.setState(
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 784d62e..3ac7885 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -104,6 +104,11 @@
     static final int VISIBLE_APP_ADJ = 100;
     static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
 
+    // This is a process that was recently TOP and moved to FGS. Continue to treat it almost
+    // like a foreground app for a while.
+    // @see TOP_TO_FGS_GRACE_PERIOD
+    static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;
+
     // This is the process running the current foreground app.  We'd really
     // rather not kill it!
     static final int FOREGROUND_APP_ADJ = 0;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 144f18b..d3dc0f3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -198,6 +198,7 @@
     long lastRequestedGc;       // When we last asked the app to do a gc
     long lastLowMemory;         // When we last told the app that memory is low
     long lastProviderTime;      // The last time someone else was using a provider in this process.
+    long lastTopTime;           // The last time the process was in the TOP state or greater.
     boolean reportLowMemory;    // Set to true when waiting to report low mem
     boolean empty;              // Is this an empty background process?
     boolean cached;             // Is this a cached process?
@@ -415,6 +416,11 @@
             TimeUtils.formatDuration(lastProviderTime, nowUptime, pw);
             pw.println();
         }
+        if (lastTopTime > 0) {
+            pw.print(prefix); pw.print("lastTopTime=");
+            TimeUtils.formatDuration(lastTopTime, nowUptime, pw);
+            pw.println();
+        }
         if (hasStartedServices) {
             pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
         }
diff --git a/services/core/java/com/android/server/biometrics/BiometricPromptService.java b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
index 29eda8b..d1371d1 100644
--- a/services/core/java/com/android/server/biometrics/BiometricPromptService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
@@ -41,7 +41,6 @@
 import android.util.Slog;
 
 import com.android.internal.R;
-import com.android.internal.os.SomeArgs;
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
@@ -133,6 +132,12 @@
             // AppOps and foreground check.
             checkPermission();
 
+            if (token == null || receiver == null || opPackageName == null || bundle == null
+                    || dialogReceiver == null) {
+                Slog.e(TAG, "Unable to authenticate, one or more null arguments");
+                return;
+            }
+
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
@@ -166,6 +171,11 @@
                 throws RemoteException {
             checkPermission();
 
+            if (token == null || opPackageName == null) {
+                Slog.e(TAG, "Unable to cancel, one or more null arguments");
+                return;
+            }
+
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index d16c277..a8f7259 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -68,6 +68,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -112,10 +113,8 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringConfiguration;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
@@ -149,7 +148,7 @@
     protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
 
     private static final Class[] messageClasses = {
-            Tethering.class, TetherMasterSM.class, TetherInterfaceStateMachine.class
+            Tethering.class, TetherMasterSM.class, IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
@@ -159,21 +158,21 @@
             .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
 
     private static class TetherState {
-        public final TetherInterfaceStateMachine stateMachine;
+        public final IpServer ipServer;
         public int lastState;
         public int lastError;
 
-        public TetherState(TetherInterfaceStateMachine sm) {
-            stateMachine = sm;
+        public TetherState(IpServer ipServer) {
+            this.ipServer = ipServer;
             // Assume all state machines start out available and with no errors.
-            lastState = IControlsTethering.STATE_AVAILABLE;
+            lastState = IpServer.STATE_AVAILABLE;
             lastError = TETHER_ERROR_NO_ERROR;
         }
 
         public boolean isCurrentlyServing() {
             switch (lastState) {
-                case IControlsTethering.STATE_TETHERED:
-                case IControlsTethering.STATE_LOCAL_ONLY:
+                case IpServer.STATE_TETHERED:
+                case IpServer.STATE_LOCAL_ONLY:
                     return true;
                 default:
                     return false;
@@ -198,7 +197,7 @@
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     // TODO: Figure out how to merge this and other downstream-tracking objects
     // into a single coherent structure.
-    private final HashSet<TetherInterfaceStateMachine> mForwardedDownstreams;
+    private final HashSet<IpServer> mForwardedDownstreams;
     private final VersionedBroadcastListener mCarrierConfigChange;
     private final TetheringDependencies mDeps;
 
@@ -604,7 +603,7 @@
     }
 
     public int tether(String iface) {
-        return tether(iface, IControlsTethering.STATE_TETHERED);
+        return tether(iface, IpServer.STATE_TETHERED);
     }
 
     private int tether(String iface, int requestedState) {
@@ -617,7 +616,7 @@
             }
             // Ignore the error status of the interface.  If the interface is available,
             // the errors are referring to past tethering attempts anyway.
-            if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
+            if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
                 Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
@@ -626,8 +625,7 @@
             // return an error.
             //
             // TODO: reexamine the threading and messaging model.
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -644,8 +642,7 @@
                 Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
-            tetherState.stateMachine.sendMessage(
-                    TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -689,11 +686,11 @@
                 String iface = mTetherStates.keyAt(i);
                 if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
                     erroredList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     availableList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+                } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
                     localOnlyList.add(iface);
-                } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     if (cfg.isUsb(iface)) {
                         usbTethered = true;
                     } else if (cfg.isWifi(iface)) {
@@ -882,10 +879,10 @@
             synchronized (Tethering.this.mPublicSync) {
                 if (!usbConnected && mRndisEnabled) {
                     // Turn off tethering if it was enabled and there is a disconnect.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
-                    tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
+                    tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
                 }
                 mRndisEnabled = usbConfigured && rndisEnabled;
             }
@@ -959,15 +956,15 @@
         if (!TextUtils.isEmpty(ifname)) {
             final TetherState ts = mTetherStates.get(ifname);
             if (ts != null) {
-                ts.stateMachine.unwanted();
+                ts.ipServer.unwanted();
                 return;
             }
         }
 
         for (int i = 0; i < mTetherStates.size(); i++) {
-            TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
-            if (tism.interfaceType() == TETHERING_WIFI) {
-                tism.unwanted();
+            final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
+            if (ipServer.interfaceType() == TETHERING_WIFI) {
+                ipServer.unwanted();
                 return;
             }
         }
@@ -978,15 +975,15 @@
     }
 
     private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
-        // Map wifiIpMode values to IControlsTethering serving states, inferring
+        // Map wifiIpMode values to IpServer.Callback serving states, inferring
         // from mWifiTetherRequested as a final "best guess".
         final int ipServingMode;
         switch (wifiIpMode) {
             case IFACE_IP_MODE_TETHERED:
-                ipServingMode = IControlsTethering.STATE_TETHERED;
+                ipServingMode = IpServer.STATE_TETHERED;
                 break;
             case IFACE_IP_MODE_LOCAL_ONLY:
-                ipServingMode = IControlsTethering.STATE_LOCAL_ONLY;
+                ipServingMode = IpServer.STATE_LOCAL_ONLY;
                 break;
             default:
                 mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
@@ -1041,12 +1038,12 @@
     private void changeInterfaceState(String ifname, int requestedState) {
         final int result;
         switch (requestedState) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 result = untether(ifname);
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 result = tether(ifname, requestedState);
                 break;
             default:
@@ -1104,7 +1101,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState == IpServer.STATE_TETHERED) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1117,7 +1114,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
+                if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1177,7 +1174,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState != IControlsTethering.STATE_TETHERED) {
+                if (tetherState.lastState != IpServer.STATE_TETHERED) {
                     continue;  // Skip interfaces that aren't tethered.
                 }
                 String iface = mTetherStates.keyAt(i);
@@ -1231,7 +1228,7 @@
         // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
         // so that the garbage collector does not clean up the state machine before it has a chance
         // to tear itself down.
-        private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+        private final ArrayList<IpServer> mNotifyList;
         private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
         private final OffloadWrapper mOffload;
 
@@ -1268,17 +1265,19 @@
             public boolean processMessage(Message message) {
                 logMessage(this, message.what);
                 switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
                         transitionTo(mTetherModeAliveState);
                         break;
-                    case EVENT_IFACE_SERVING_STATE_INACTIVE:
-                        who = (TetherInterfaceStateMachine) message.obj;
+                    }
+                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
                         break;
+                    }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES:
                         // Silently ignore these for now.
                         break;
@@ -1410,8 +1409,8 @@
 
         protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
             mCurrentUpstreamIfaceSet = ifaces;
-            for (TetherInterfaceStateMachine sm : mNotifyList) {
-                sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
+            for (IpServer ipServer : mNotifyList) {
+                ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
             }
         }
 
@@ -1420,13 +1419,13 @@
             mOffload.updateUpstreamNetworkState(ns);
         }
 
-        private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateActive(int mode, IpServer who) {
             if (mNotifyList.indexOf(who) < 0) {
                 mNotifyList.add(who);
                 mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
             }
 
-            if (mode == IControlsTethering.STATE_TETHERED) {
+            if (mode == IpServer.STATE_TETHERED) {
                 // No need to notify OffloadController just yet as there are no
                 // "offload-able" prefixes to pass along. This will handled
                 // when the TISM informs Tethering of its LinkProperties.
@@ -1441,10 +1440,10 @@
                 final WifiManager mgr = getWifiManager();
                 final String iface = who.interfaceName();
                 switch (mode) {
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
                         break;
                     default:
@@ -1454,7 +1453,7 @@
             }
         }
 
-        private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
+        private void handleInterfaceServingStateInactive(IpServer who) {
             mNotifyList.remove(who);
             mIPv6TetheringCoordinator.removeActiveDownstream(who);
             mOffload.excludeDownstreamInterface(who.interfaceName());
@@ -1563,10 +1562,10 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         handleInterfaceServingStateActive(message.arg1, who);
-                        who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+                        who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                                 mCurrentUpstreamIfaceSet);
                         // If there has been a change and an upstream is now
                         // desired, kick off the selection process.
@@ -1577,7 +1576,7 @@
                         break;
                     }
                     case EVENT_IFACE_SERVING_STATE_INACTIVE: {
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         handleInterfaceServingStateInactive(who);
 
@@ -1591,7 +1590,7 @@
                         if (DBG) {
                             Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
                                     " live requests:");
-                            for (TetherInterfaceStateMachine o : mNotifyList) {
+                            for (IpServer o : mNotifyList) {
                                 Log.d(TAG, "  " + o);
                             }
                         }
@@ -1605,7 +1604,7 @@
                     }
                     case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
                         final LinkProperties newLp = (LinkProperties) message.obj;
-                        if (message.arg1 == IControlsTethering.STATE_TETHERED) {
+                        if (message.arg1 == IpServer.STATE_TETHERED) {
                             mOffload.updateDownstreamLinkProperties(newLp);
                         } else {
                             mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
@@ -1650,7 +1649,7 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine) message.obj;
+                        IpServer who = (IpServer) message.obj;
                         who.sendMessage(mErrorNotification);
                         break;
                     case CMD_CLEAR_ERROR:
@@ -1665,8 +1664,8 @@
 
             void notify(int msgType) {
                 mErrorNotification = msgType;
-                for (TetherInterfaceStateMachine sm : mNotifyList) {
-                    sm.sendMessage(msgType);
+                for (IpServer ipServer : mNotifyList) {
+                    ipServer.sendMessage(msgType);
                 }
             }
 
@@ -1676,7 +1675,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingEnabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
             }
         }
 
@@ -1684,7 +1683,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setIpForwardingDisabled");
-                notify(TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR);
+                notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
             }
         }
 
@@ -1692,7 +1691,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in startTethering");
-                notify(TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR);
+                notify(IpServer.CMD_START_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1703,7 +1702,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in stopTethering");
-                notify(TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR);
+                notify(IpServer.CMD_STOP_TETHERING_ERROR);
                 try {
                     mNMService.setIpForwardingEnabled(false);
                 } catch (Exception e) {}
@@ -1714,7 +1713,7 @@
             @Override
             public void enter() {
                 Log.e(TAG, "Error in setDnsForwarders");
-                notify(TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR);
+                notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
                 try {
                     mNMService.stopTethering();
                 } catch (Exception e) {}
@@ -1771,15 +1770,15 @@
 
                 // Maybe add prefixes or addresses for downstreams, depending on
                 // the IP serving mode of each.
-                for (TetherInterfaceStateMachine tism : mNotifyList) {
-                    final LinkProperties lp = tism.linkProperties();
+                for (IpServer ipServer : mNotifyList) {
+                    final LinkProperties lp = ipServer.linkProperties();
 
-                    switch (tism.servingMode()) {
-                        case IControlsTethering.STATE_UNAVAILABLE:
-                        case IControlsTethering.STATE_AVAILABLE:
+                    switch (ipServer.servingMode()) {
+                        case IpServer.STATE_UNAVAILABLE:
+                        case IpServer.STATE_AVAILABLE:
                             // No usable LinkProperties in these states.
                             continue;
-                        case IControlsTethering.STATE_TETHERED:
+                        case IpServer.STATE_TETHERED:
                             // Only add IPv4 /32 and IPv6 /128 prefixes. The
                             // directly-connected prefixes will be sent as
                             // downstream "offload-able" prefixes.
@@ -1789,7 +1788,7 @@
                                 localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
                             }
                             break;
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case IpServer.STATE_LOCAL_ONLY:
                             // Add prefixes covering all local IPs.
                             localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
                             break;
@@ -1826,16 +1825,16 @@
                 pw.print(iface + " - ");
 
                 switch (tetherState.lastState) {
-                    case IControlsTethering.STATE_UNAVAILABLE:
+                    case IpServer.STATE_UNAVAILABLE:
                         pw.print("UnavailableState");
                         break;
-                    case IControlsTethering.STATE_AVAILABLE:
+                    case IpServer.STATE_AVAILABLE:
                         pw.print("AvailableState");
                         break;
-                    case IControlsTethering.STATE_TETHERED:
+                    case IpServer.STATE_TETHERED:
                         pw.print("TetheredState");
                         break;
-                    case IControlsTethering.STATE_LOCAL_ONLY:
+                    case IpServer.STATE_LOCAL_ONLY:
                         pw.print("LocalHotspotState");
                         break;
                     default:
@@ -1873,28 +1872,26 @@
         return false;
     }
 
-    private IControlsTethering makeControlCallback(String ifname) {
-        return new IControlsTethering() {
+    private IpServer.Callback makeControlCallback() {
+        return new IpServer.Callback() {
             @Override
-            public void updateInterfaceState(
-                    TetherInterfaceStateMachine who, int state, int lastError) {
-                notifyInterfaceStateChange(ifname, who, state, lastError);
+            public void updateInterfaceState(IpServer who, int state, int lastError) {
+                notifyInterfaceStateChange(who, state, lastError);
             }
 
             @Override
-            public void updateLinkProperties(
-                    TetherInterfaceStateMachine who, LinkProperties newLp) {
-                notifyLinkPropertiesChanged(ifname, who, newLp);
+            public void updateLinkProperties(IpServer who, LinkProperties newLp) {
+                notifyLinkPropertiesChanged(who, newLp);
             }
         };
     }
 
     // TODO: Move into TetherMasterSM.
-    private void notifyInterfaceStateChange(
-            String iface, TetherInterfaceStateMachine who, int state, int error) {
+    private void notifyInterfaceStateChange(IpServer who, int state, int error) {
+        final String iface = who.interfaceName();
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 tetherState.lastState = state;
                 tetherState.lastError = error;
             } else {
@@ -1908,7 +1905,7 @@
             // Notify that we're tethering (or not) this interface.
             // This is how data saver for instance knows if the user explicitly
             // turned on tethering (thus keeping us from being in data saver mode).
-            mPolicyManager.onTetheringChanged(iface, state == IControlsTethering.STATE_TETHERED);
+            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
         } catch (RemoteException e) {
             // Not really very much we can do here.
         }
@@ -1921,12 +1918,12 @@
         }
         int which;
         switch (state) {
-            case IControlsTethering.STATE_UNAVAILABLE:
-            case IControlsTethering.STATE_AVAILABLE:
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
-            case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_ONLY:
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
@@ -1937,12 +1934,12 @@
         sendTetherStateChangedBroadcast();
     }
 
-    private void notifyLinkPropertiesChanged(String iface, TetherInterfaceStateMachine who,
-                                             LinkProperties newLp) {
+    private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
+        final String iface = who.interfaceName();
         final int state;
         synchronized (mPublicSync) {
             final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.stateMachine.equals(who)) {
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
                 state = tetherState.lastState;
             } else {
                 mLog.log("got notification from stale iface " + iface);
@@ -1952,7 +1949,7 @@
 
         mLog.log(String.format(
                 "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
-                iface, IControlsTethering.getStateString(state), newLp));
+                iface, IpServer.getStateString(state), newLp));
         final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
         mTetherMasterSM.sendMessage(which, state, 0, newLp);
     }
@@ -1976,11 +1973,11 @@
 
         mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
         final TetherState tetherState = new TetherState(
-                new TetherInterfaceStateMachine(
-                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
-                    makeControlCallback(iface), mConfig.enableLegacyDhcpServer, mDeps));
+                new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
+                             mDeps.getIpServerDependencies()));
         mTetherStates.put(iface, tetherState);
-        tetherState.stateMachine.start();
+        tetherState.ipServer.start();
     }
 
     private void stopTrackingInterfaceLocked(final String iface) {
@@ -1989,36 +1986,11 @@
             mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
             return;
         }
-        tetherState.stateMachine.stop();
+        tetherState.ipServer.stop();
         mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
         mTetherStates.remove(iface);
     }
 
-    private static String getIPv4DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        return getInterfaceForDestination(ns.linkProperties, Inet4Address.ANY);
-    }
-
-    private static String getIPv6DefaultRouteInterface(NetworkState ns) {
-        if (ns == null) return null;
-        // An upstream network's IPv6 capability is currently only useful if it
-        // can be 64share'd downstream (RFC 7278). For now, that means mobile
-        // upstream networks only.
-        if (ns.networkCapabilities == null ||
-                !ns.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-            return null;
-        }
-
-        return getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY);
-    }
-
-    private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
-        final RouteInfo ri = (lp != null)
-                ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
-                : null;
-        return (ri != null) ? ri.getInterface() : null;
-    }
-
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
deleted file mode 100644
index 2b81347..0000000
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ /dev/null
@@ -1,66 +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.connectivity.tethering;
-
-import android.net.LinkProperties;
-
-/**
- * @hide
- *
- * Interface with methods necessary to notify that a given interface is ready for tethering.
- *
- * Rename to something more representative, e.g. IpServingControlCallback.
- *
- * All methods MUST be called on the TetherMasterSM main Looper's thread.
- */
-public class IControlsTethering {
-    public static final int STATE_UNAVAILABLE = 0;
-    public static final int STATE_AVAILABLE   = 1;
-    public static final int STATE_TETHERED    = 2;
-    public static final int STATE_LOCAL_ONLY  = 3;
-
-    public static String getStateString(int state) {
-        switch (state) {
-            case STATE_UNAVAILABLE: return "UNAVAILABLE";
-            case STATE_AVAILABLE:   return "AVAILABLE";
-            case STATE_TETHERED:    return "TETHERED";
-            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
-        }
-        return "UNKNOWN: " + state;
-    }
-
-    /**
-     * Notify that |who| has changed its tethering state.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param state one of IControlsTethering.STATE_*
-     * @param lastError one of ConnectivityManager.TETHER_ERROR_*
-     */
-    public void updateInterfaceState(TetherInterfaceStateMachine who, int state, int lastError) {}
-
-    /**
-     * Notify that |who| has new LinkProperties.
-     *
-     * TODO: Remove the need for the |who| argument.
-     *
-     * @param who corresponding instance of a TetherInterfaceStateMachine
-     * @param newLp the new LinkProperties to report
-     */
-    public void updateLinkProperties(TetherInterfaceStateMachine who, LinkProperties newLp) {}
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index ba67c94..1000148 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity.tethering;
 
 import android.net.ConnectivityManager;
+import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -50,19 +51,19 @@
     private static final boolean VDBG = false;
 
     private static class Downstream {
-        public final TetherInterfaceStateMachine tism;
-        public final int mode;  // IControlsTethering.STATE_*
+        public final IpServer ipServer;
+        public final int mode;  // IpServer.STATE_*
         // Used to append to a ULA /48, constructing a ULA /64 for local use.
         public final short subnetId;
 
-        Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) {
-            this.tism = tism;
+        Downstream(IpServer ipServer, int mode, short subnetId) {
+            this.ipServer = ipServer;
             this.mode = mode;
             this.subnetId = subnetId;
         }
     }
 
-    private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+    private final ArrayList<IpServer> mNotifyList;
     private final SharedLog mLog;
     // NOTE: mActiveDownstreams is a list and not a hash data structure because
     // we keep active downstreams in arrival order.  This is done so /64s can
@@ -74,8 +75,7 @@
     private short mNextSubnetId;
     private NetworkState mUpstreamNetworkState;
 
-    public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
-                                    SharedLog log) {
+    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
         mNotifyList = notifyList;
         mLog = log.forSubComponent(TAG);
         mActiveDownstreams = new LinkedList<>();
@@ -83,7 +83,7 @@
         mNextSubnetId = 0;
     }
 
-    public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) {
+    public void addActiveDownstream(IpServer downstream, int mode) {
         if (findDownstream(downstream) == null) {
             // Adding a new downstream appends it to the list. Adding a
             // downstream a second time without first removing it has no effect.
@@ -98,7 +98,7 @@
         }
     }
 
-    public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+    public void removeActiveDownstream(IpServer downstream) {
         stopIPv6TetheringOn(downstream);
         if (mActiveDownstreams.remove(findDownstream(downstream))) {
             updateIPv6TetheringInterfaces();
@@ -133,8 +133,8 @@
     }
 
     private void stopIPv6TetheringOnAllInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            stopIPv6TetheringOn(sm);
+        for (IpServer ipServer : mNotifyList) {
+            stopIPv6TetheringOn(ipServer);
         }
     }
 
@@ -156,28 +156,28 @@
     }
 
     private void updateIPv6TetheringInterfaces() {
-        for (TetherInterfaceStateMachine sm : mNotifyList) {
-            final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+        for (IpServer ipServer : mNotifyList) {
+            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
+            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
             break;
         }
     }
 
-    private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
-        if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
+    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
+        if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
             // TODO: Figure out IPv6 support on PAN interfaces.
             return null;
         }
 
-        final Downstream ds = findDownstream(sm);
+        final Downstream ds = findDownstream(ipServer);
         if (ds == null) return null;
 
-        if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
+        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
             // Build a Unique Locally-assigned Prefix configuration.
             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
         }
 
-        // This downstream is in IControlsTethering.STATE_TETHERED mode.
+        // This downstream is in IpServer.STATE_TETHERED mode.
         if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
             return null;
         }
@@ -188,7 +188,7 @@
         // IPv6 toward the oldest (first requested) active downstream.
 
         final Downstream currentActive = mActiveDownstreams.peek();
-        if (currentActive != null && currentActive.tism == sm) {
+        if (currentActive != null && currentActive.ipServer == ipServer) {
             final LinkProperties lp = getIPv6OnlyLinkProperties(
                     mUpstreamNetworkState.linkProperties);
             if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
@@ -199,9 +199,9 @@
         return null;
     }
 
-    Downstream findDownstream(TetherInterfaceStateMachine tism) {
+    Downstream findDownstream(IpServer ipServer) {
         for (Downstream ds : mActiveDownstreams) {
-            if (ds.tism == tism) return ds;
+            if (ds.ipServer == ipServer) return ds;
         }
         return null;
     }
@@ -304,7 +304,7 @@
                 ns.linkProperties);
     }
 
-    private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
-        sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+    private static void stopIPv6TetheringOn(IpServer ipServer) {
+        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index caa867c..8b40069 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@
 import android.net.NetworkRequest;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetdService;
@@ -49,20 +50,12 @@
     }
 
     public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-            ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+            ArrayList<IpServer> notifyList, SharedLog log) {
         return new IPv6TetheringCoordinator(notifyList, log);
     }
 
-    public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-        return new RouterAdvertisementDaemon(ifParams);
-    }
-
-    public InterfaceParams getInterfaceParams(String ifName) {
-        return InterfaceParams.getByName(ifName);
-    }
-
-    public INetd getNetdService() {
-        return NetdService.getInstance();
+    public IpServer.Dependencies getIpServerDependencies() {
+        return new IpServer.Dependencies();
     }
 
     public boolean isTetheringSupported() {
@@ -72,9 +65,4 @@
     public NetworkRequest getDefaultNetworkRequest() {
         return null;
     }
-
-    public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface, DhcpServingParams params,
-            SharedLog log) {
-        return new DhcpServer(looper, iface, params, log);
-    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 49f33e0..b2287ac 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -16,6 +16,7 @@
 package com.android.server.inputmethod;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -129,10 +130,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
-import com.android.internal.inputmethod.InputMethodUtils;
-import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.HandlerCaller;
@@ -152,6 +149,8 @@
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -572,6 +571,11 @@
     IBinder mCurToken;
 
     /**
+     * The displayId of current active input method.
+     */
+    int mCurTokenDisplayId = INVALID_DISPLAY;
+
+    /**
      * If non-null, this is the input method service we are currently connected
      * to.
      */
@@ -1866,7 +1870,9 @@
         mCurAttribute = attribute;
 
         // Check if the input method is changing.
-        if (mCurId != null && mCurId.equals(mCurMethodId)) {
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(
+                mCurFocusedWindow);
+        if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
@@ -1930,14 +1936,20 @@
                 com.android.internal.R.string.input_method_binding_label);
         mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(mCurFocusedWindow);
+        mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
+
         if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
             mLastBindTime = SystemClock.uptimeMillis();
             mHaveConnection = true;
             mCurId = info.getId();
             mCurToken = new Binder();
             try {
-                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
-                mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, DEFAULT_DISPLAY);
+                if (DEBUG) {
+                    Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
+                            + mCurTokenDisplayId);
+                }
+                mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
             return new InputBindResult(
@@ -1964,8 +1976,9 @@
                     return;
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                        MSG_INITIALIZE_IME, mCurMethod, mCurToken));
+                // Dispatch display id for InputMethodService to update context display.
+                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
                     requestClientSessionLocked(mCurClient);
@@ -2011,15 +2024,19 @@
 
         if (mCurToken != null) {
             try {
-                if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
+                if (DEBUG) {
+                    Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+                            + mCurTokenDisplayId);
+                }
                 if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
                     // The current IME is shown. Hence an IME switch (transition) is happening.
                     mWindowManagerInternal.saveLastInputMethodWindowForTransition();
                 }
-                mIWindowManager.removeWindowToken(mCurToken, DEFAULT_DISPLAY);
+                mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
             mCurToken = null;
+            mCurTokenDisplayId = INVALID_DISPLAY;
         }
 
         mCurId = null;
@@ -2785,6 +2802,15 @@
                                 // soft input window if it is shown.
                                 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
                                 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
+
+                                // If focused display changed, we should unbind current method
+                                // to make app window in previous display relayout after Ime
+                                // window token removed.
+                                final int newFocusDisplayId =
+                                        mWindowManagerInternal.getDisplayIdForWindow(windowToken);
+                                if (newFocusDisplayId != mCurTokenDisplayId) {
+                                    unbindCurrentMethodLocked(false);
+                                }
                             }
                         } else if (isTextEditor && doAutoShow && (softInputMode &
                                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3151,7 +3177,7 @@
      */
     @Override
     public int getInputMethodWindowVisibleHeight() {
-        return mWindowManagerInternal.getInputMethodWindowVisibleHeight();
+        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
     }
 
     @BinderThread
@@ -3352,9 +3378,12 @@
             case MSG_INITIALIZE_IME:
                 args = (SomeArgs)msg.obj;
                 try {
-                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
+                    if (DEBUG) {
+                        Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
+                                + msg.arg1);
+                    }
                     final IBinder token = (IBinder) args.arg2;
-                    ((IInputMethod) args.arg1).initializeInternal(token,
+                    ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
                             new InputMethodPrivilegedOperationsImpl(this, token));
                 } catch (RemoteException e) {
                 }
@@ -4516,6 +4545,7 @@
             p.println("  mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
                     + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
             p.println("  mCurToken=" + mCurToken);
+            p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
             p.println("  mCurIntent=" + mCurIntent);
             method = mCurMethod;
             p.println("  mCurMethod=" + mCurMethod);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
similarity index 98%
rename from core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
rename to services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 14ac2f6..77b2fee 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -27,7 +27,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
+import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -41,13 +41,11 @@
 
 /**
  * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
- * <p>
- * This class is designed to be used from and only from
- * {@link com.android.server.InputMethodManagerService} by using
- * {@link com.android.server.InputMethodManagerService#mMethodMap} as a global lock.
- * </p>
+ *
+ * <p>This class is designed to be used from and only from {@link InputMethodManagerService} by
+ * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p>
  */
-public class InputMethodSubtypeSwitchingController {
+final class InputMethodSubtypeSwitchingController {
     private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
     private static final boolean DEBUG = false;
     private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
similarity index 98%
rename from core/java/com/android/internal/inputmethod/InputMethodUtils.java
rename to services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 1410ff9..e951b27 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
@@ -53,10 +53,14 @@
 import java.util.Locale;
 
 /**
- * InputMethodManagerUtils contains some static methods that provides IME informations.
- * This methods are supposed to be used in both the framework and the Settings application.
+ * This class provides random static utility methods for {@link InputMethodManagerService} and its
+ * utility classes.
+ *
+ * <p>This class is intentionally package-private.  Utility methods here are tightly coupled with
+ * implementation details in {@link InputMethodManagerService}.  Hence this class is not suitable
+ * for other components to directly use.</p>
  */
-public class InputMethodUtils {
+final class InputMethodUtils {
     public static final boolean DEBUG = false;
     public static final int NOT_A_SUBTYPE_ID = -1;
     public static final String SUBTYPE_MODE_ANY = null;
@@ -1294,7 +1298,6 @@
         }
     }
 
-    @VisibleForTesting
     public static boolean isSoftInputModeStateVisibleAllowed(
             int targetSdkVersion, int controlFlags) {
         if (targetSdkVersion < Build.VERSION_CODES.P) {
@@ -1309,4 +1312,5 @@
         }
         return true;
     }
+
 }
diff --git a/services/core/java/com/android/server/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
new file mode 100644
index 0000000..4958ece
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
@@ -0,0 +1,206 @@
+/*
+ * 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.inputmethod;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.icu.util.ULocale;
+import android.os.LocaleList;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+final class LocaleUtils {
+    public interface LocaleExtractor<T> {
+        @Nullable
+        Locale get(@Nullable T source);
+    }
+
+    /**
+     * Calculates a matching score for the single desired locale.
+     *
+     * @see LocaleUtils#filterByLanguage(List, LocaleExtractor, LocaleList, ArrayList)
+     *
+     * @param supported The locale supported by IME subtype.
+     * @param desired The locale preferred by user.
+     * @return A score based on the locale matching for the default subtype enabling.
+     */
+    @IntRange(from=1, to=3)
+    private static byte calculateMatchingSubScore(@NonNull final ULocale supported,
+            @NonNull final ULocale desired) {
+        // Assuming supported/desired is fully expanded.
+        if (supported.equals(desired)) {
+            return 3;  // Exact match.
+        }
+
+        // Skip language matching since it was already done in calculateMatchingScore.
+
+        final String supportedScript = supported.getScript();
+        if (supportedScript.isEmpty() || !supportedScript.equals(desired.getScript())) {
+            // TODO: Need subscript matching. For example, Hanb should match with Bopo.
+            return 1;
+        }
+
+        final String supportedCountry = supported.getCountry();
+        if (supportedCountry.isEmpty() || !supportedCountry.equals(desired.getCountry())) {
+            return 2;
+        }
+
+        // Ignore others e.g. variants, extensions.
+        return 3;
+    }
+
+    private static final class ScoreEntry implements Comparable<ScoreEntry> {
+        public int mIndex = -1;
+        @NonNull public final byte[] mScore;  // matching score of the i-th system languages.
+
+        ScoreEntry(@NonNull byte[] score, int index) {
+            mScore = new byte[score.length];
+            set(score, index);
+        }
+
+        private void set(@NonNull byte[] score, int index) {
+            for (int i = 0; i < mScore.length; ++i) {
+                mScore[i] = score[i];
+            }
+            mIndex = index;
+        }
+
+        /**
+         * Update score and index if the given score is better than this.
+         */
+        public void updateIfBetter(@NonNull byte[] score, int index) {
+            if (compare(mScore, score) == -1) {  // mScore < score
+                set(score, index);
+            }
+        }
+
+        /**
+         * Provides comaprison for bytes[].
+         *
+         * <p> Comparison does as follows. If the first value of {@code left} is larger than the
+         * first value of {@code right}, {@code left} is large than {@code right}.  If the first
+         * value of {@code left} is less than the first value of {@code right}, {@code left} is less
+         * than {@code right}. If the first value of {@code left} and the first value of
+         * {@code right} is equal, do the same comparison to the next value. Finally if all values
+         * in {@code left} and {@code right} are equal, {@code left} and {@code right} is equal.</p>
+         *
+         * @param left The length must be equal to {@code right}.
+         * @param right The length must be equal to {@code left}.
+         * @return 1 if {@code left} is larger than {@code right}. -1 if {@code left} is less than
+         * {@code right}. 0 if {@code left} and {@code right} is equal.
+         */
+        @IntRange(from=-1, to=1)
+        private static int compare(@NonNull byte[] left, @NonNull byte[] right) {
+            for (int i = 0; i < left.length; ++i) {
+                if (left[i] > right[i]) {
+                    return 1;
+                } else if (left[i] < right[i]) {
+                    return -1;
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public int compareTo(final ScoreEntry other) {
+            return -1 * compare(mScore, other.mScore);  // Order by descending order.
+        }
+    }
+
+    /**
+     * Filters the given items based on language preferences.
+     *
+     * <p>For each language found in {@code preferredLocales}, this method tries to copy at most
+     * one best-match item from {@code source} to {@code dest}.  For example, if
+     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLocales},
+     * this method tries to copy at most one English locale, at most one Japanese, and at most one
+     * French locale from {@code source} to {@code dest}.  Here the best matching English locale
+     * will be searched from {@code source} based on matching score. For the score design, see
+     * {@link LocaleUtils#calculateMatchingSubScore(ULocale, ULocale)}</p>
+     *
+     * @param sources Source items to be filtered.
+     * @param extractor Type converter from the source items to {@link Locale} object.
+     * @param preferredLocales Ordered list of locales with which the input items will be
+     * filtered.
+     * @param dest Destination into which the filtered items will be added.
+     * @param <T> Type of the data items.
+     */
+    public static <T> void filterByLanguage(
+            @NonNull List<T> sources,
+            @NonNull LocaleExtractor<T> extractor,
+            @NonNull LocaleList preferredLocales,
+            @NonNull ArrayList<T> dest) {
+        if (preferredLocales.isEmpty()) {
+            return;
+        }
+
+        final int numPreferredLocales = preferredLocales.size();
+        final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
+        final byte[] score = new byte[numPreferredLocales];
+        final ULocale[] preferredULocaleCache = new ULocale[numPreferredLocales];
+
+        final int sourceSize = sources.size();
+        for (int i = 0; i < sourceSize; ++i) {
+            final Locale locale = extractor.get(sources.get(i));
+            if (locale == null) {
+                continue;
+            }
+
+            boolean canSkip = true;
+            for (int j = 0; j < numPreferredLocales; ++j) {
+                final Locale preferredLocale = preferredLocales.get(j);
+                if (!TextUtils.equals(locale.getLanguage(), preferredLocale.getLanguage())) {
+                    score[j] = 0;
+                    continue;
+                }
+                if (preferredULocaleCache[j] == null) {
+                    preferredULocaleCache[j] = ULocale.addLikelySubtags(
+                            ULocale.forLocale(preferredLocale));
+                }
+                score[j] = calculateMatchingSubScore(
+                        preferredULocaleCache[j],
+                        ULocale.addLikelySubtags(ULocale.forLocale(locale)));
+                if (canSkip && score[j] != 0) {
+                    canSkip = false;
+                }
+            }
+            if (canSkip) {
+                continue;
+            }
+
+            final String lang = locale.getLanguage();
+            final ScoreEntry bestScore = scoreboard.get(lang);
+            if (bestScore == null) {
+                scoreboard.put(lang, new ScoreEntry(score, i));
+            } else {
+                bestScore.updateIfBetter(score, i);
+            }
+        }
+
+        final ScoreEntry[] result = scoreboard.values().toArray(new ScoreEntry[scoreboard.size()]);
+        Arrays.sort(result);
+        for (final ScoreEntry entry : result) {
+            dest.add(sources.get(entry.mIndex));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 7751f5f..050a075 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -178,6 +178,10 @@
         }
     }
 
+    protected int getBindFlags() {
+        return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
+    }
+
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
 
     private ManagedServiceInfo newServiceInfo(IInterface service,
@@ -1064,9 +1068,9 @@
                 }
             };
             if (!mContext.bindServiceAsUser(intent,
-                serviceConnection,
-                BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
-                new UserHandle(userid))) {
+                    serviceConnection,
+                    getBindFlags(),
+                    new UserHandle(userid))) {
                 mServicesBound.remove(servicesBindingTag);
                 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
                 return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 03b7652..33f0172 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -33,6 +33,10 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE;
+import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_FOREGROUND_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -345,7 +349,7 @@
     private String mSoundNotificationKey;
     private String mVibrateNotificationKey;
 
-    private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
+    private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
             new SparseArray<>();
     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
     private int mListenerHints;  // right now, all hints are global
@@ -1784,10 +1788,10 @@
     private ArrayList<ComponentName> getSuppressors() {
         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
-            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+            ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
 
-            for (ManagedServiceInfo info : serviceInfoList) {
-                names.add(info.component);
+            for (ComponentName info : serviceInfoList) {
+                names.add(info);
             }
         }
 
@@ -1803,11 +1807,10 @@
 
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
             final int hint = mListenersDisablingEffects.keyAt(i);
-            final ArraySet<ManagedServiceInfo> listeners =
-                    mListenersDisablingEffects.valueAt(i);
+            final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
 
             if (hints == 0 || (hint & hints) == hint) {
-                removed = removed || listeners.remove(info);
+                removed |= listeners.remove(info.component);
             }
         }
 
@@ -1830,18 +1833,18 @@
 
     private void addDisabledHint(ManagedServiceInfo info, int hint) {
         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
-            mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
+            mListenersDisablingEffects.put(hint, new ArraySet<>());
         }
 
-        ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
-        hintListeners.add(info);
+        ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
+        hintListeners.add(info.component);
     }
 
     private int calculateHints() {
         int hints = 0;
         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
             int hint = mListenersDisablingEffects.keyAt(i);
-            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+            ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
 
             if (!serviceInfoList.isEmpty()) {
                 hints |= hint;
@@ -2955,6 +2958,21 @@
         }
 
         @Override
+        public void clearRequestedListenerHints(INotificationListener token) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationLock) {
+                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                    removeDisabledHints(info);
+                    updateListenerHintsLocked();
+                    updateEffectsSuppressorLocked();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void requestHintsFromListener(INotificationListener token, int hints) {
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -3860,11 +3878,12 @@
 
                 proto.write(
                     ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
-                final ArraySet<ManagedServiceInfo> listeners =
+                final ArraySet<ComponentName> listeners =
                     mListenersDisablingEffects.valueAt(i);
                 for (int j = 0; j < listeners.size(); j++) {
-                    final ManagedServiceInfo listener = listeners.valueAt(i);
-                    listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
+                    final ComponentName componentName = listeners.valueAt(i);
+                    componentName.writeToProto(proto,
+                            ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
                 }
 
                 proto.end(effectsToken);
@@ -4003,15 +4022,14 @@
                     if (i > 0) pw.print(';');
                     pw.print("hint[" + hint + "]:");
 
-                    final ArraySet<ManagedServiceInfo> listeners =
-                            mListenersDisablingEffects.valueAt(i);
+                    final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
                     final int listenerSize = listeners.size();
 
                     for (int j = 0; j < listenerSize; j++) {
                         if (i > 0) pw.print(',');
-                        final ManagedServiceInfo listener = listeners.valueAt(i);
+                        final ComponentName listener = listeners.valueAt(i);
                         if (listener != null) {
-                            pw.print(listener.component);
+                            pw.print(listener);
                         }
                     }
                 }
@@ -4070,25 +4088,30 @@
         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
                 int userId) {
             checkCallerIsSystem();
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (mNotificationLock) {
-                        removeForegroundServiceFlagByListLocked(
-                                mEnqueuedNotifications, pkg, notificationId, userId);
-                        removeForegroundServiceFlagByListLocked(
-                                mNotificationList, pkg, notificationId, userId);
+            mHandler.post(() -> {
+                synchronized (mNotificationLock) {
+                    // strip flag from all enqueued notifications. listeners will be informed
+                    // in post runnable.
+                    List<NotificationRecord> enqueued = findNotificationsByListLocked(
+                            mEnqueuedNotifications, pkg, null, notificationId, userId);
+                    for (int i = 0; i < enqueued.size(); i++) {
+                        removeForegroundServiceFlagLocked(enqueued.get(i));
+                    }
+
+                    // if posted notification exists, strip its flag and tell listeners
+                    NotificationRecord r = findNotificationByListLocked(
+                            mNotificationList, pkg, null, notificationId, userId);
+                    if (r != null) {
+                        removeForegroundServiceFlagLocked(r);
+                        mRankingHelper.sort(mNotificationList);
+                        mListeners.notifyPostedLocked(r, r);
                     }
                 }
             });
         }
 
         @GuardedBy("mNotificationLock")
-        private void removeForegroundServiceFlagByListLocked(
-                ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
-                int userId) {
-            NotificationRecord r = findNotificationByListLocked(
-                    notificationList, pkg, null, notificationId, userId);
+        private void removeForegroundServiceFlagLocked(NotificationRecord r) {
             if (r == null) {
                 return;
             }
@@ -4099,8 +4122,6 @@
             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
             sbn.getNotification().flags =
                     (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
-            mRankingHelper.sort(mNotificationList);
-            mListeners.notifyPostedLocked(r, r);
         }
     };
 
@@ -4381,22 +4402,12 @@
     }
 
     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
-        final String pkg = r.sbn.getPackageName();
-        final int callingUid = r.sbn.getUid();
-
-        final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
-        if (isPackageSuspended) {
-            Slog.e(TAG, "Suppressing notification from package due to package "
-                    + "suspended by administrator.");
-            usageStats.registerSuspendedByAdmin(r);
-            return isPackageSuspended;
-        }
-        final boolean isBlocked = isBlocked(r);
-        if (isBlocked) {
+        if (isBlocked(r)) {
             Slog.e(TAG, "Suppressing notification from package by user request.");
             usageStats.registerBlocked(r);
+            return true;
         }
-        return isBlocked;
+        return false;
     }
 
     private boolean isBlocked(NotificationRecord r) {
@@ -4670,7 +4681,11 @@
                         return;
                     }
 
-                    r.setHidden(isPackageSuspendedLocked(r));
+                    final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+                    r.setHidden(isPackageSuspended);
+                    if (isPackageSuspended) {
+                        mUsageStats.registerSuspendedByAdmin(r);
+                    }
                     NotificationRecord old = mNotificationsByKey.get(key);
                     final StatusBarNotification n = r.sbn;
                     final Notification notification = n.getNotification();
@@ -6253,6 +6268,21 @@
     }
 
     @GuardedBy("mNotificationLock")
+    private List<NotificationRecord> findNotificationsByListLocked(
+            ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
+        List<NotificationRecord> matching = new ArrayList<>();
+        final int len = list.size();
+        for (int i = 0; i < len; i++) {
+            NotificationRecord r = list.get(i);
+            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
+                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
+                matching.add(r);
+            }
+        }
+        return matching;
+    }
+
+    @GuardedBy("mNotificationLock")
     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
             String key) {
         final int N = list.size();
@@ -6786,6 +6816,16 @@
         }
 
         @Override
+        protected int getBindFlags() {
+            // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE
+            // because too many 3P apps could be kept in memory as notification listeners and
+            // cause extreme memory pressure.
+            // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
+            return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
+                    | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
+        }
+
+        @Override
         protected Config getConfig() {
             Config c = new Config();
             c.caption = "notification listener";
@@ -6876,7 +6916,6 @@
                 if (!oldSbnVisible && !sbnVisible) {
                     continue;
                 }
-
                 // If the notification is hidden, don't notifyPosted listeners targeting < P.
                 // Instead, those listeners will receive notifyPosted when the notification is
                 // unhidden.
@@ -7310,7 +7349,7 @@
                 new String[]{pkg});
 
         final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
-            : Intent.ACTION_PACKAGES_UNSUSPENDED;
+                : Intent.ACTION_PACKAGES_UNSUSPENDED;
         final Intent intent = new Intent(action);
         intent.putExtras(extras);
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6ac72d3..4dd2bf2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -501,9 +501,14 @@
     }
 
     protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
-        return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
-                NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                rule.creationTime);
+        if (rule.zenPolicy != null) {
+            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, rule.zenPolicy,
+                    rule.enabled, rule.creationTime);
+        } else {
+            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
+                    NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+                    rule.creationTime);
+        }
     }
 
     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
@@ -667,6 +672,9 @@
         }
     }
 
+    /**
+     * @return user-specified default notification policy for priority only do not disturb
+     */
     public Policy getNotificationPolicy() {
         return getNotificationPolicy(mConfig);
     }
@@ -675,6 +683,9 @@
         return config == null ? null : config.toNotificationPolicy();
     }
 
+    /**
+     * Sets the global notification policy used for priority only do not disturb
+     */
     public void setNotificationPolicy(Policy policy) {
         if (policy == null || mConfig == null) return;
         synchronized (mConfig) {
@@ -770,9 +781,7 @@
             ComponentName triggeringComponent, boolean setRingerMode) {
         final String val = Integer.toString(config.hashCode());
         Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-        if (!evaluateZenMode(reason, setRingerMode)) {
-            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
-        }
+        evaluateZenMode(reason, setRingerMode);
         mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
     }
 
@@ -798,7 +807,7 @@
     }
 
     @VisibleForTesting
-    protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
+    protected void evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
         final int zenBefore = mZenMode;
         final int zen = computeZenMode();
@@ -813,7 +822,6 @@
         if (zen != zenBefore) {
             mHandler.postDispatchOnZenModeChanged();
         }
-        return true;
     }
 
     private void updateRingerModeAffectedStreams() {
@@ -822,7 +830,9 @@
         }
     }
 
+
     private int computeZenMode() {
+        // TODO: use mConfig.zenPolicy
         if (mConfig == null) return Global.ZEN_MODE_OFF;
         synchronized (mConfig) {
             if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index c738701..f1b03d1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -558,8 +558,8 @@
         @Override
         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
                 int userId) throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabled");
-            userId = handleIncomingUser(userId, "setEnabled");
+            enforceChangeOverlayPackagesPermission("setEnabledExclusive");
+            userId = handleIncomingUser(userId, "setEnabledExclusive");
             if (packageName == null || !enable) {
                 return false;
             }
@@ -578,8 +578,8 @@
         @Override
         public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
                 throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabled");
-            userId = handleIncomingUser(userId, "setEnabled");
+            enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
+            userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
             if (packageName == null) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 7d762d9..5bf323a 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -378,7 +378,7 @@
         for (int i = newIntents.size() - 1; i >= 0; --i) {
             final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
             final PackageParser.Package disabledPkg = sPackageManagerInternal
-                    .getDisabledPackage(intentInfo.activity.info.packageName);
+                    .getDisabledSystemPackage(intentInfo.activity.info.packageName);
             final List<PackageParser.Activity> systemActivities =
                     disabledPkg != null ? disabledPkg.activities : null;
             adjustPriority(systemActivities, intentInfo, setupWizardPackage);
@@ -1048,11 +1048,14 @@
                         final String otherPackageName =
                                 (other != null && other.getComponentName() != null)
                                         ? other.getComponentName().getPackageName() : "?";
-                        throw new PackageManagerException(
-                                INSTALL_FAILED_CONFLICTING_PROVIDER,
-                                "Can't install because provider name " + names[j]
-                                        + " (in package " + pkg.applicationInfo.packageName
-                                        + ") is already used by " + otherPackageName);
+                        // if we're installing over the same already-installed package, this is ok
+                        if (otherPackageName != pkg.packageName) {
+                            throw new PackageManagerException(
+                                    INSTALL_FAILED_CONFLICTING_PROVIDER,
+                                    "Can't install because provider name " + names[j]
+                                            + " (in package " + pkg.applicationInfo.packageName
+                                            + ") is already used by " + otherPackageName);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d305032..8f2833f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -59,6 +59,7 @@
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.dex.DexMetadataHelper;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
@@ -99,7 +100,6 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 
-import android.content.pm.dex.DexMetadataHelper;
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -122,7 +122,6 @@
     private static final boolean LOGD = true;
     private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
 
-    private static final int MSG_EARLY_BIND = 0;
     private static final int MSG_COMMIT = 1;
     private static final int MSG_ON_PACKAGE_INSTALLED = 2;
 
@@ -168,7 +167,6 @@
     final int userId;
     final SessionParams params;
     final long createdMillis;
-    final int defaultContainerGid;
 
     /** Staging location where client data is written. */
     final File stageDir;
@@ -285,9 +283,6 @@
         @Override
         public boolean handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_EARLY_BIND:
-                    earlyBindToDefContainer();
-                    break;
                 case MSG_COMMIT:
                     synchronized (mLock) {
                         try {
@@ -323,10 +318,6 @@
         }
     };
 
-    private void earlyBindToDefContainer() {
-        mPm.earlyBindToDefContainer();
-    }
-
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
@@ -413,19 +404,6 @@
                 }
             }
         }
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-            defaultContainerGid = UserHandle.getSharedAppGid(uid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        // attempt to bind to the DefContainer as early as possible
-        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_EARLY_BIND));
-        }
     }
 
     public SessionInfo generateInfo() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cacdccb..91af0ec 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -88,8 +88,6 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
-import static android.system.OsConstants.O_CREAT;
-import static android.system.OsConstants.O_RDWR;
 
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
@@ -113,7 +111,8 @@
 import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+import static com.android.server.pm.permission.PermissionsState
+        .PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -137,7 +136,6 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
-import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AppsQueryHelper;
@@ -207,14 +205,12 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
-import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
 import android.os.PatternMatcher;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -273,12 +269,10 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
@@ -310,7 +304,8 @@
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy
+        .DefaultPermissionGrantedCallback;
 import com.android.server.pm.permission.PermissionManagerInternal;
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionManagerService;
@@ -551,12 +546,6 @@
 
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
-    public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
-
-    public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
-            DEFAULT_CONTAINER_PACKAGE,
-            "com.android.defcontainer.DefaultContainerService");
-
     private static final String KILL_APP_REASON_GIDS_CHANGED =
             "permission grant or revoke changed gids";
 
@@ -729,6 +718,8 @@
     @GuardedBy("mPackages")
     final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
 
+    private PackageManager mPackageManager;
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -1238,18 +1229,9 @@
     }
     final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts();
 
-    // Service Connection to remote media container service to copy
-    // package uri's from external media onto secure containers
-    // or internal storage.
-    private IMediaContainerService mContainerService = null;
-
     static final int SEND_PENDING_BROADCAST = 1;
-    static final int MCS_BOUND = 3;
     static final int INIT_COPY = 5;
-    static final int MCS_UNBIND = 6;
     static final int POST_INSTALL = 9;
-    static final int MCS_RECONNECT = 10;
-    static final int MCS_GIVE_UP = 11;
     static final int WRITE_SETTINGS = 13;
     static final int WRITE_PACKAGE_RESTRICTIONS = 14;
     static final int PACKAGE_VERIFIED = 15;
@@ -1258,7 +1240,6 @@
     static final int INTENT_FILTER_VERIFIED = 18;
     static final int WRITE_PACKAGE_LIST = 19;
     static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
-    static final int DEF_CONTAINER_BIND = 21;
 
     static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
 
@@ -1273,21 +1254,6 @@
     // Stores a list of users whose package restrictions file needs to be updated
     private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
 
-    final private DefaultContainerConnection mDefContainerConn =
-            new DefaultContainerConnection();
-    class DefaultContainerConnection implements ServiceConnection {
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
-            final IMediaContainerService imcs = IMediaContainerService.Stub
-                    .asInterface(Binder.allowBlocking(service));
-            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
-        }
-    }
-
     // Recordkeeping of restore-after-install operations that are currently in flight
     // between the Package Manager and the Backup Manager
     static class PostInstallData {
@@ -1346,31 +1312,6 @@
     private final CompilerStats mCompilerStats = new CompilerStats();
 
     class PackageHandler extends Handler {
-        private boolean mBound = false;
-        final ArrayList<HandlerParams> mPendingInstalls =
-                new ArrayList<>();
-
-        private boolean connectToService() {
-            if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
-            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
-            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-            if (mContext.bindServiceAsUser(service, mDefContainerConn,
-                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                mBound = true;
-                return true;
-            }
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            return false;
-        }
-
-        private void disconnectService() {
-            mContainerService = null;
-            mBound = false;
-            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-            mContext.unbindService(mDefContainerConn);
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-        }
 
         PackageHandler(Looper looper) {
             super(looper);
@@ -1386,167 +1327,18 @@
 
         void doHandleMessage(Message msg) {
             switch (msg.what) {
-                case DEF_CONTAINER_BIND:
-                    if (!mBound) {
-                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "earlyBindingMCS",
-                                System.identityHashCode(mHandler));
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                        }
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "earlyBindingMCS",
-                                System.identityHashCode(mHandler));
-                    }
-                    break;
                 case INIT_COPY: {
                     HandlerParams params = (HandlerParams) msg.obj;
-                    int idx = mPendingInstalls.size();
-                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
-                    // If a bind was already initiated we dont really
-                    // need to do anything. The pending install
-                    // will be processed later on.
-                    if (!mBound) {
-                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                System.identityHashCode(mHandler));
-                        // If this is the only one pending we might
-                        // have to bind to the service again.
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                            params.serviceError();
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                    System.identityHashCode(mHandler));
-                            if (params.traceMethod != null) {
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
-                                        params.traceCookie);
-                            }
-                            return;
-                        } else {
-                            // Once we bind to the service, the first
-                            // pending request will be processed.
-                            mPendingInstalls.add(idx, params);
-                        }
-                    } else {
-                        mPendingInstalls.add(idx, params);
-                        // Already bound to the service. Just make
-                        // sure we trigger off processing the first request.
-                        if (idx == 0) {
-                            mHandler.sendEmptyMessage(MCS_BOUND);
-                        }
+                    if (params != null) {
+                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
+                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                                System.identityHashCode(params));
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
+                        params.startCopy();
+                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                     }
                     break;
                 }
-                case MCS_BOUND: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
-                    if (msg.obj != null) {
-                        mContainerService = (IMediaContainerService) msg.obj;
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                System.identityHashCode(mHandler));
-                    }
-                    if (mContainerService == null) {
-                        if (!mBound) {
-                            // Something seriously wrong since we are not bound and we are not
-                            // waiting for connection. Bail out.
-                            Slog.e(TAG, "Cannot bind to media container service");
-                            for (HandlerParams params : mPendingInstalls) {
-                                // Indicate service bind error
-                                params.serviceError();
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                        System.identityHashCode(params));
-                                if (params.traceMethod != null) {
-                                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
-                                            params.traceMethod, params.traceCookie);
-                                }
-                            }
-                            mPendingInstalls.clear();
-                        } else {
-                            Slog.w(TAG, "Waiting to connect to media container service");
-                        }
-                    } else if (mPendingInstalls.size() > 0) {
-                        HandlerParams params = mPendingInstalls.get(0);
-                        if (params != null) {
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                    System.identityHashCode(params));
-                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
-                            if (params.startCopy()) {
-                                // We are done...  look for more work or to
-                                // go idle.
-                                if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                        "Checking for more work or unbind...");
-                                // Delete pending install
-                                if (mPendingInstalls.size() > 0) {
-                                    mPendingInstalls.remove(0);
-                                }
-                                if (mPendingInstalls.size() == 0) {
-                                    if (mBound) {
-                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                                "Posting delayed MCS_UNBIND");
-                                        removeMessages(MCS_UNBIND);
-                                        Message ubmsg = obtainMessage(MCS_UNBIND);
-                                        // Unbind after a little delay, to avoid
-                                        // continual thrashing.
-                                        sendMessageDelayed(ubmsg, 10000);
-                                    }
-                                } else {
-                                    // There are more pending requests in queue.
-                                    // Just post MCS_BOUND message to trigger processing
-                                    // of next pending install.
-                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                            "Posting MCS_BOUND for next work");
-                                    mHandler.sendEmptyMessage(MCS_BOUND);
-                                }
-                            }
-                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                        }
-                    } else {
-                        // Should never happen ideally.
-                        Slog.w(TAG, "Empty queue");
-                    }
-                    break;
-                }
-                case MCS_RECONNECT: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
-                    if (mPendingInstalls.size() > 0) {
-                        if (mBound) {
-                            disconnectService();
-                        }
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                            for (HandlerParams params : mPendingInstalls) {
-                                // Indicate service bind error
-                                params.serviceError();
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                        System.identityHashCode(params));
-                            }
-                            mPendingInstalls.clear();
-                        }
-                    }
-                    break;
-                }
-                case MCS_UNBIND: {
-                    // If there is no actual work left, then time to unbind.
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
-
-                    if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
-                        if (mBound) {
-                            if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
-
-                            disconnectService();
-                        }
-                    } else if (mPendingInstalls.size() > 0) {
-                        // There are more pending requests in queue.
-                        // Just post MCS_BOUND message to trigger processing
-                        // of next pending install.
-                        mHandler.sendEmptyMessage(MCS_BOUND);
-                    }
-
-                    break;
-                }
-                case MCS_GIVE_UP: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
-                    HandlerParams params = mPendingInstalls.remove(0);
-                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                            System.identityHashCode(params));
-                    break;
-                }
                 case SEND_PENDING_BROADCAST: {
                     String packages[];
                     ArrayList<String> components[];
@@ -1685,11 +1477,7 @@
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                             broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_ALLOW, user);
-                            try {
-                                ret = args.copyApk(mContainerService, true);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Could not contact the ContainerService");
-                            }
+                            ret = args.copyApk();
                         } else {
                             broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_REJECT, user);
@@ -1699,7 +1487,6 @@
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
                         processPendingInstall(args, ret);
-                        mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
                     break;
                 }
@@ -1724,14 +1511,9 @@
 
                         int ret;
                         if (state.isInstallAllowed()) {
-                            ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                             broadcastPackageVerified(verificationId, originUri,
                                     response.code, state.getInstallArgs().getUser());
-                            try {
-                                ret = args.copyApk(mContainerService, true);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Could not contact the ContainerService");
-                            }
+                            ret = args.copyApk();
                         } else {
                             ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                         }
@@ -1740,7 +1522,6 @@
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
                         processPendingInstall(args, ret);
-                        mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
 
                     break;
@@ -8805,7 +8586,10 @@
                             null /* originalPkgSetting */, null, parseFlags, scanFlags,
                             (pkg == mPlatformPackage), user);
                     applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-                    scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
+                        scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
+                    }
                 }
             }
         }
@@ -10028,6 +9812,11 @@
         /** Whether or not the package scan was successful */
         public final boolean success;
         /**
+         * Whether or not the original PackageSetting needs to be updated with this result on
+         * commit.
+         */
+        public final boolean existingSettingCopied;
+        /**
          * The final package settings. This may be the same object passed in
          * the {@link ScanRequest}, but, with modified values.
          */
@@ -10037,11 +9826,12 @@
         public ScanResult(
                 ScanRequest request, boolean success,
                 @Nullable PackageSetting pkgSetting,
-                @Nullable List<String> changedAbiCodePath) {
+                @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied) {
             this.request = request;
             this.success = success;
             this.pkgSetting = pkgSetting;
             this.changedAbiCodePath = changedAbiCodePath;
+            this.existingSettingCopied = existingSettingCopied;
         }
     }
 
@@ -10118,26 +9908,34 @@
     private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
             PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
             PackageParser.Package pkg) {
-        if (disabledPkgSetting != null) {
+
+        // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
+        // the correct isSystem value now that we don't disable system packages before scan.
+        final PackageSetting systemPkgSetting =
+                (scanFlags & SCAN_NEW_INSTALL) != 0 && disabledPkgSetting == null
+                        && pkgSetting != null && pkgSetting.isSystem()
+                        ? pkgSetting
+                        : disabledPkgSetting;
+        if (systemPkgSetting != null)  {
             // updated system application, must at least have SCAN_AS_SYSTEM
             scanFlags |= SCAN_AS_SYSTEM;
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                 scanFlags |= SCAN_AS_PRIVILEGED;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) {
                 scanFlags |= SCAN_AS_OEM;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
                 scanFlags |= SCAN_AS_VENDOR;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
                 scanFlags |= SCAN_AS_PRODUCT;
             }
-            if ((disabledPkgSetting.pkgPrivateFlags
+            if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
                 scanFlags |= SCAN_AS_PRODUCT_SERVICES;
             }
@@ -10267,11 +10065,18 @@
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
         final UserHandle user = request.user;
         final String realPkgName = request.realPkgName;
-        final PackageSetting pkgSetting = result.pkgSetting;
         final List<String> changedAbiCodePath = result.changedAbiCodePath;
-        final boolean newPkgSettingCreated = (result.pkgSetting != request.pkgSetting);
-
-        if (newPkgSettingCreated) {
+        final PackageSetting pkgSetting;
+        if (result.existingSettingCopied) {
+            pkgSetting = request.pkgSetting;
+            pkgSetting.updateFrom(result.pkgSetting);
+            pkg.mExtras = pkgSetting;
+            if (pkgSetting.sharedUser != null
+                    && pkgSetting.sharedUser.removePackage(result.pkgSetting)) {
+                pkgSetting.sharedUser.addPackage(pkgSetting);
+            }
+        } else {
+            pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
                 mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
             }
@@ -10578,7 +10383,6 @@
         String primaryCpuAbiFromSettings = null;
         String secondaryCpuAbiFromSettings = null;
         boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
-
         if (!needToDeriveAbi) {
             if (pkgSetting != null) {
                 primaryCpuAbiFromSettings = pkgSetting.primaryCpuAbiString;
@@ -10622,6 +10426,11 @@
                     UserManagerService.getInstance(), usesStaticLibraries,
                     pkg.usesStaticLibrariesVersions);
         } else {
+            if (!createNewPackage) {
+                // make a deep copy to avoid modifying any existing system state.
+                pkgSetting = new PackageSetting(pkgSetting);
+                pkgSetting.pkg = pkg;
+            }
             // REMOVE SharedUserSetting from method; update in a separate call.
             //
             // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
@@ -10654,8 +10463,10 @@
             final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
             setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
         }
-
-        if (disabledPkgSetting != null) {
+        // TODO(patb): see if we can do away with disabled check here.
+        if (disabledPkgSetting != null
+                || (0 != (scanFlags & SCAN_NEW_INSTALL)
+                && pkgSetting != null && pkgSetting.isSystem())) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         }
 
@@ -10838,7 +10649,8 @@
             pkgSetting.volumeUuid = volumeUuid;
         }
 
-        return new ScanResult(request, true, pkgSetting, changedAbiCodePath);
+        return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
+                !createNewPackage /* existingSettingCopied */);
     }
 
     /**
@@ -11053,7 +10865,7 @@
             }
 
             // A package name must be unique; don't allow duplicates
-            if (mPackages.containsKey(pkg.packageName)) {
+            if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
                 throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                         "Application package " + pkg.packageName
                         + " already installed.  Skipping duplicate.");
@@ -11062,7 +10874,8 @@
             if (pkg.applicationInfo.isStaticSharedLibrary()) {
                 // Static libs have a synthetic package name containing the version
                 // but we still want the base name to be unique.
-                if (mPackages.containsKey(pkg.manifestPackageName)) {
+                if ((scanFlags & SCAN_NEW_INSTALL) == 0
+                        && mPackages.containsKey(pkg.manifestPackageName)) {
                     throw new PackageManagerException(
                             "Duplicate static shared lib provider package");
                 }
@@ -12151,7 +11964,9 @@
         // Remove the parent package setting
         PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps != null) {
-            removePackageLI(ps, chatty);
+            removePackageLI(ps.name, chatty);
+        } else if (DEBUG_REMOVE && chatty) {
+            Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
         }
         // Remove the child package setting
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
@@ -12159,23 +11974,22 @@
             PackageParser.Package childPkg = pkg.childPackages.get(i);
             ps = (PackageSetting) childPkg.mExtras;
             if (ps != null) {
-                removePackageLI(ps, chatty);
+                removePackageLI(ps.name, chatty);
             }
         }
     }
 
-    void removePackageLI(PackageSetting ps, boolean chatty) {
+    void removePackageLI(String packageName, boolean chatty) {
         if (DEBUG_INSTALL) {
             if (chatty)
-                Log.d(TAG, "Removing package " + ps.name);
+                Log.d(TAG, "Removing package " + packageName);
         }
 
         // writer
         synchronized (mPackages) {
-            mPackages.remove(ps.name);
-            final PackageParser.Package pkg = ps.pkg;
-            if (pkg != null) {
-                cleanPackageDataStructuresLILPw(pkg, chatty);
+            final PackageParser.Package removedPackage = mPackages.remove(packageName);
+            if (removedPackage != null) {
+                cleanPackageDataStructuresLILPw(removedPackage, chatty);
             }
         }
     }
@@ -12430,14 +12244,6 @@
         return installReason;
     }
 
-    /**
-     * Attempts to bind to the default container service explicitly instead of doing so lazily on
-     * install commit.
-     */
-    void earlyBindToDefContainer() {
-        mHandler.sendMessage(mHandler.obtainMessage(DEF_CONTAINER_BIND));
-    }
-
     void installStage(String packageName, File stagedDir,
             IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user,
@@ -13784,14 +13590,6 @@
     }
 
     private abstract class HandlerParams {
-        private static final int MAX_RETRIES = 4;
-
-        /**
-         * Number of times startCopy() has been attempted and had a non-fatal
-         * error.
-         */
-        private int mRetries = 0;
-
         /** User handle for the user requesting the information or installation. */
         private final UserHandle mUser;
         String traceMethod;
@@ -13815,37 +13613,13 @@
             return this;
         }
 
-        final boolean startCopy() {
-            boolean res;
-            try {
-                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-
-                if (++mRetries > MAX_RETRIES) {
-                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
-                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
-                    handleServiceError();
-                    return false;
-                } else {
-                    handleStartCopy();
-                    res = true;
-                }
-            } catch (RemoteException e) {
-                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
-                mHandler.sendEmptyMessage(MCS_RECONNECT);
-                res = false;
-            }
-            handleReturnCode();
-            return res;
-        }
-
-        final void serviceError() {
-            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
-            handleServiceError();
+        final void startCopy() {
+            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
+            handleStartCopy();
             handleReturnCode();
         }
 
-        abstract void handleStartCopy() throws RemoteException;
-        abstract void handleServiceError();
+        abstract void handleStartCopy();
         abstract void handleReturnCode();
     }
 
@@ -14088,7 +13862,7 @@
          * policy if needed and then create install arguments based
          * on the install location.
          */
-        public void handleStartCopy() throws RemoteException {
+        public void handleStartCopy() {
             int ret = PackageManager.INSTALL_SUCCEEDED;
 
             // If we're already staged, we've firmly committed to an install location
@@ -14114,8 +13888,8 @@
                 Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
-                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
-                        packageAbiOverride);
+                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+                        origin.resolvedPath, installFlags, packageAbiOverride);
 
                 if (DEBUG_INSTANT && ephemeral) {
                     Slog.v(TAG, "pkgLite for install: " + pkgLite);
@@ -14132,15 +13906,16 @@
                     final long lowThreshold = storage.getStorageLowBytes(
                             Environment.getDataDirectory());
 
-                    final long sizeBytes = mContainerService.calculateInstalledSize(
+                    final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                             origin.resolvedPath, packageAbiOverride);
-
-                    try {
-                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
-                        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
-                                installFlags, packageAbiOverride);
-                    } catch (InstallerException e) {
-                        Slog.w(TAG, "Failed to free cache", e);
+                    if (sizeBytes >= 0) {
+                        try {
+                            mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
+                            pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+                                    origin.resolvedPath, installFlags, packageAbiOverride);
+                        } catch (InstallerException e) {
+                            Slog.w(TAG, "Failed to free cache", e);
+                        }
                     }
 
                     /*
@@ -14351,7 +14126,7 @@
                      * No package verification is enabled, so immediately start
                      * the remote call to initiate copy using temporary file.
                      */
-                    ret = args.copyApk(mContainerService, true);
+                    ret = args.copyApk();
                 }
             }
 
@@ -14360,19 +14135,10 @@
 
         @Override
         void handleReturnCode() {
-            // If mArgs is null, then MCS couldn't be reached. When it
-            // reconnects, it will try again to install. At that point, this
-            // will succeed.
             if (mArgs != null) {
                 processPendingInstall(mArgs, mRet);
             }
         }
-
-        @Override
-        void handleServiceError() {
-            mArgs = createInstallArgs(this);
-            mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-        }
     }
 
     private InstallArgs createInstallArgs(InstallParams params) {
@@ -14439,7 +14205,7 @@
             this.installReason = installReason;
         }
 
-        abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
+        abstract int copyApk();
         abstract int doPreInstall(int status);
 
         /**
@@ -14547,16 +14313,16 @@
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
         }
 
-        int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+        int copyApk() {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
             try {
-                return doCopyApk(imcs, temp);
+                return doCopyApk();
             } finally {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
         }
 
-        private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+        private int doCopyApk() {
             if (origin.staged) {
                 if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                 codeFile = origin.file;
@@ -14575,25 +14341,8 @@
                 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
             }
 
-            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
-                @Override
-                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
-                    if (!FileUtils.isValidExtFilename(name)) {
-                        throw new IllegalArgumentException("Invalid filename: " + name);
-                    }
-                    try {
-                        final File file = new File(codeFile, name);
-                        final FileDescriptor fd = Os.open(file.getAbsolutePath(),
-                                O_RDWR | O_CREAT, 0644);
-                        Os.chmod(file.getAbsolutePath(), 0644);
-                        return new ParcelFileDescriptor(fd);
-                    } catch (ErrnoException e) {
-                        throw new RemoteException("Failed to open: " + e.getMessage());
-                    }
-                }
-            };
-
-            int ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
+            int ret = PackageManagerServiceUtils.copyPackage(
+                    origin.file.getAbsolutePath(), codeFile);
             if (ret != PackageManager.INSTALL_SUCCEEDED) {
                 Slog.e(TAG, "Failed to copy package");
                 return ret;
@@ -14754,7 +14503,7 @@
                     params.installReason);
         }
 
-        int copyApk(IMediaContainerService imcs, boolean temp) {
+        int copyApk() {
             if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
                     + move.fromUuid + " to " + move.toUuid);
             synchronized (mInstaller) {
@@ -14941,68 +14690,6 @@
         String origPermission;
     }
 
-    /*
-     * Install a non-existing package.
-     */
-    private void installNewPackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
-            String volumeUuid, PackageInstalledInfo res, int installReason) {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
-
-        // Remember this for later, in case we need to rollback this install
-        String pkgName = pkg.packageName;
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
-
-        synchronized(mPackages) {
-            final String renamedPackage = mSettings.getRenamedPackageLPr(pkgName);
-            if (renamedPackage != null) {
-                // A package with the same name is already installed, though
-                // it has been renamed to an older name.  The package we
-                // are trying to install should be installed as an update to
-                // the existing one, but that has not been requested, so bail.
-                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
-                        + " without first uninstalling package running as "
-                        + renamedPackage);
-                return;
-            }
-            if (mPackages.containsKey(pkgName)) {
-                // Don't allow installation over an existing package with the same name.
-                res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
-                        + " without first uninstalling.");
-                return;
-            }
-        }
-
-        try {
-            final PackageParser.Package newPackage;
-            List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags, scanFlags,
-                    System.currentTimeMillis(), user);
-            commitSuccessfulScanResults(scanResults);
-            // TODO(b/109941548): Child packages may return >1 result with the first being the base;
-            // we need to treat child packages as an atomic install and remove this hack
-            final ScanResult basePackageScanResult = scanResults.get(0);
-            newPackage = basePackageScanResult.pkgSetting.pkg;
-            updateSettingsLI(newPackage, installerPackageName, null, res, user, installReason);
-
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                prepareAppDataAfterInstallLIF(newPackage);
-            } else {
-                // Remove package from internal structures, but keep around any
-                // data that might have already existed
-                deletePackageLIF(pkgName, UserHandle.ALL, false, null,
-                        PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
-            }
-        } catch (PackageManagerException e) {
-            destroyAppDataLIF(pkg, UserHandle.USER_ALL,
-                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-            destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);
-            res.setError("Package couldn't be installed in " + pkg.codePath, e);
-        }
-
-        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-    }
-
     private static void updateDigest(MessageDigest digest, File file) throws IOException {
         try (DigestInputStream digestStream =
                 new DigestInputStream(new FileInputStream(file), digest)) {
@@ -15010,482 +14697,6 @@
         }
     }
 
-    private void replacePackageLIF(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, String installerPackageName,
-            PackageInstalledInfo res, int installReason) {
-        final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
-
-        final PackageParser.Package oldPackage;
-        final PackageSetting ps;
-        final String pkgName = pkg.packageName;
-        final int[] allUsers;
-        final int[] installedUsers;
-
-        synchronized(mPackages) {
-            oldPackage = mPackages.get(pkgName);
-            if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
-
-            // don't allow upgrade to target a release SDK from a pre-release SDK
-            final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
-                    == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
-            final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
-                    == android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
-            if (oldTargetsPreRelease
-                    && !newTargetsPreRelease
-                    && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
-                Slog.w(TAG, "Can't install package targeting released sdk");
-                res.setReturnCode(PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
-                return;
-            }
-
-            ps = mSettings.mPackages.get(pkgName);
-
-            // verify signatures are valid
-            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
-            if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
-                if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
-                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                            "New package not signed by keys specified by upgrade-keysets: "
-                                    + pkgName);
-                    return;
-                }
-            } else {
-
-                // default to original signature matching
-                if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
-                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
-                                && !oldPackage.mSigningDetails.checkCapability(
-                                        pkg.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
-                    res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                            "New package has a different signature: " + pkgName);
-                    return;
-                }
-            }
-
-            // don't allow a system upgrade unless the upgrade hash matches
-            if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
-                final byte[] digestBytes;
-                try {
-                    final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                    updateDigest(digest, new File(pkg.baseCodePath));
-                    if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-                        for (String path : pkg.splitCodePaths) {
-                            updateDigest(digest, new File(path));
-                        }
-                    }
-                    digestBytes = digest.digest();
-                } catch (NoSuchAlgorithmException | IOException e) {
-                    res.setError(INSTALL_FAILED_INVALID_APK,
-                            "Could not compute hash: " + pkgName);
-                    return;
-                }
-                if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
-                    res.setError(INSTALL_FAILED_INVALID_APK,
-                            "New package fails restrict-update check: " + pkgName);
-                    return;
-                }
-                // retain upgrade restriction
-                pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
-            }
-
-            // Check for shared user id changes
-            String invalidPackageName =
-                    getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
-            if (invalidPackageName != null) {
-                res.setError(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
-                        "Package " + invalidPackageName + " tried to change user "
-                                + oldPackage.mSharedUserId);
-                return;
-            }
-
-            // check if the new package supports all of the abis which the old package supports
-            boolean oldPkgSupportMultiArch = oldPackage.applicationInfo.secondaryCpuAbi != null;
-            boolean newPkgSupportMultiArch = pkg.applicationInfo.secondaryCpuAbi != null;
-            if (isSystemApp(oldPackage) && oldPkgSupportMultiArch && !newPkgSupportMultiArch) {
-                res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                        "Update to package " + pkgName + " doesn't support multi arch");
-                return;
-            }
-
-            // In case of rollback, remember per-user/profile install state
-            allUsers = sUserManager.getUserIds();
-            installedUsers = ps.queryInstalledUsers(allUsers, true);
-
-            // don't allow an upgrade from full to ephemeral
-            if (isInstantApp) {
-                if (user == null || user.getIdentifier() == UserHandle.USER_ALL) {
-                    for (int currentUser : allUsers) {
-                        if (!ps.getInstantApp(currentUser)) {
-                            // can't downgrade from full to instant
-                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
-                                    + " for user: " + currentUser);
-                            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-                            return;
-                        }
-                    }
-                } else if (!ps.getInstantApp(user.getIdentifier())) {
-                    // can't downgrade from full to instant
-                    Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
-                            + " for user: " + user.getIdentifier());
-                    res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-                    return;
-                }
-            }
-        }
-
-        // Update what is removed
-        res.removedInfo = new PackageRemovedInfo(this);
-        res.removedInfo.uid = oldPackage.applicationInfo.uid;
-        res.removedInfo.removedPackage = oldPackage.packageName;
-        res.removedInfo.installerPackageName = ps.installerPackageName;
-        res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
-        res.removedInfo.isUpdate = true;
-        res.removedInfo.origUsers = installedUsers;
-        res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
-        for (int i = 0; i < installedUsers.length; i++) {
-            final int userId = installedUsers[i];
-            res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
-        }
-
-        final int childCount = (oldPackage.childPackages != null)
-                ? oldPackage.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            boolean childPackageUpdated = false;
-            PackageParser.Package childPkg = oldPackage.childPackages.get(i);
-            final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-            if (res.addedChildPackages != null) {
-                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
-                if (childRes != null) {
-                    childRes.removedInfo.uid = childPkg.applicationInfo.uid;
-                    childRes.removedInfo.removedPackage = childPkg.packageName;
-                    if (childPs != null) {
-                        childRes.removedInfo.installerPackageName = childPs.installerPackageName;
-                    }
-                    childRes.removedInfo.isUpdate = true;
-                    childRes.removedInfo.installReasons = res.removedInfo.installReasons;
-                    childPackageUpdated = true;
-                }
-            }
-            if (!childPackageUpdated) {
-                PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
-                childRemovedRes.removedPackage = childPkg.packageName;
-                if (childPs != null) {
-                    childRemovedRes.installerPackageName = childPs.installerPackageName;
-                }
-                childRemovedRes.isUpdate = false;
-                childRemovedRes.dataRemoved = true;
-                synchronized (mPackages) {
-                    if (childPs != null) {
-                        childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
-                    }
-                }
-                if (res.removedInfo.removedChildPackages == null) {
-                    res.removedInfo.removedChildPackages = new ArrayMap<>();
-                }
-                res.removedInfo.removedChildPackages.put(childPkg.packageName, childRemovedRes);
-            }
-        }
-
-        boolean sysPkg = (isSystemApp(oldPackage));
-        if (sysPkg) {
-            // Set the system/privileged/oem/vendor/product flags as needed
-            final boolean privileged = isPrivilegedApp(oldPackage);
-            final boolean oem = isOemApp(oldPackage);
-            final boolean vendor = isVendorApp(oldPackage);
-            final boolean product = isProductApp(oldPackage);
-            final boolean productServices = isProductServicesApp(oldPackage);
-
-            final @ParseFlags int systemParseFlags = parseFlags;
-            final @ScanFlags int systemScanFlags = scanFlags
-                    | SCAN_AS_SYSTEM
-                    | (privileged ? SCAN_AS_PRIVILEGED : 0)
-                    | (oem ? SCAN_AS_OEM : 0)
-                    | (vendor ? SCAN_AS_VENDOR : 0)
-                    | (product ? SCAN_AS_PRODUCT : 0)
-                    | (productServices ? SCAN_AS_PRODUCT_SERVICES : 0);
-
-            replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
-                    user, allUsers, installerPackageName, res, installReason);
-        } else {
-            replaceNonSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, installerPackageName, res, installReason);
-        }
-    }
-
-    private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user, int[] allUsers,
-            String installerPackageName, PackageInstalledInfo res, int installReason) {
-        if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
-                + deletedPackage);
-
-        String pkgName = deletedPackage.packageName;
-        boolean deletedPkg = true;
-        boolean addedPkg = false;
-        boolean updatedSettings = false;
-        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
-        final int deleteFlags = PackageManager.DELETE_KEEP_DATA
-                | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
-
-        final long origUpdateTime = (pkg.mExtras != null)
-                ? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
-
-        // First delete the existing package while retaining the data directory
-        if (!deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
-                res.removedInfo, true, pkg)) {
-            // If the existing package wasn't successfully deleted
-            res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
-            deletedPkg = false;
-        } else {
-            // Successfully deleted the old package; proceed with replace.
-
-            // If deleted package lived in a container, give users a chance to
-            // relinquish resources before killing.
-            if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
-                if (DEBUG_INSTALL) {
-                    Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
-                }
-                final int[] uidArray = new int[] { deletedPackage.applicationInfo.uid };
-                final ArrayList<String> pkgList = new ArrayList<>(1);
-                pkgList.add(deletedPackage.applicationInfo.packageName);
-                sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
-            }
-
-            clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
-                    | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-
-            try {
-                final List<ScanResult> scanResults = scanPackageTracedLI(pkg, parseFlags,
-                        scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
-                commitSuccessfulScanResults(scanResults);
-                final PackageParser.Package newPackage = scanResults.get(0).pkgSetting.pkg;
-                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
-                        installReason);
-
-                // Update the in-memory copy of the previous code paths.
-                PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (!killApp) {
-                    if (ps.oldCodePaths == null) {
-                        ps.oldCodePaths = new ArraySet<>();
-                    }
-                    Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
-                    if (deletedPackage.splitCodePaths != null) {
-                        Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
-                    }
-                } else {
-                    ps.oldCodePaths = null;
-                }
-                if (ps.childPackageNames != null) {
-                    for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
-                        final String childPkgName = ps.childPackageNames.get(i);
-                        final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
-                        childPs.oldCodePaths = ps.oldCodePaths;
-                    }
-                }
-                prepareAppDataAfterInstallLIF(newPackage);
-                addedPkg = true;
-                mDexManager.notifyPackageUpdated(newPackage.packageName,
-                        newPackage.baseCodePath, newPackage.splitCodePaths);
-            } catch (PackageManagerException e) {
-                res.setError("Package couldn't be installed in " + pkg.codePath, e);
-            }
-        }
-
-        if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName);
-
-            // Revert all internal state mutations and added folders for the failed install
-            if (addedPkg) {
-                deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
-                        res.removedInfo, true, null);
-            }
-
-            // Restore the old package
-            if (deletedPkg) {
-                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
-                File restoreFile = new File(deletedPackage.codePath);
-                // Parse old package
-                boolean oldExternal = isExternal(deletedPackage);
-                int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
-                        (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
-                        (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
-                int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
-                try {
-                    scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime,
-                            null);
-                } catch (PackageManagerException e) {
-                    Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
-                            + e.getMessage());
-                    return;
-                }
-
-                synchronized (mPackages) {
-                    // Ensure the installer package name up to date
-                    setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
-                    // Update permissions for restored package
-                    mPermissionManager.updatePermissions(
-                            deletedPackage.packageName, deletedPackage, false, mPackages.values(),
-                            mPermissionCallback);
-
-                    mSettings.writeLPr();
-                }
-
-                Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
-            }
-        } else {
-            synchronized (mPackages) {
-                PackageSetting ps = mSettings.getPackageLPr(pkg.packageName);
-                if (ps != null) {
-                    res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
-                    if (res.removedInfo.removedChildPackages != null) {
-                        final int childCount = res.removedInfo.removedChildPackages.size();
-                        // Iterate in reverse as we may modify the collection
-                        for (int i = childCount - 1; i >= 0; i--) {
-                            String childPackageName = res.removedInfo.removedChildPackages.keyAt(i);
-                            if (res.addedChildPackages.containsKey(childPackageName)) {
-                                res.removedInfo.removedChildPackages.removeAt(i);
-                            } else {
-                                PackageRemovedInfo childInfo = res.removedInfo
-                                        .removedChildPackages.valueAt(i);
-                                childInfo.removedForAllUsers = mPackages.get(
-                                        childInfo.removedPackage) == null;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
-            PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, UserHandle user,
-            int[] allUsers, String installerPackageName, PackageInstalledInfo res,
-            int installReason) {
-        if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
-                + ", old=" + deletedPackage);
-
-        final boolean disabledSystem;
-
-        // Remove existing system package
-        removePackageLI(deletedPackage, true);
-
-        synchronized (mPackages) {
-            disabledSystem = disableSystemPackageLPw(deletedPackage, pkg);
-        }
-        if (!disabledSystem) {
-            // We didn't need to disable the .apk as a current system package,
-            // which means we are replacing another update that is already
-            // installed.  We need to make sure to delete the older one's .apk.
-            res.removedInfo.args = createInstallArgsForExisting(0,
-                    deletedPackage.applicationInfo.getCodePath(),
-                    deletedPackage.applicationInfo.getResourcePath(),
-                    getAppDexInstructionSets(deletedPackage.applicationInfo));
-        } else {
-            res.removedInfo.args = null;
-        }
-
-        // Successfully disabled the old package. Now proceed with re-installation
-        clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
-                | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-
-        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-        pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
-                ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
-
-        PackageParser.Package newPackage = null;
-        try {
-            final List<ScanResult> scanResults =
-                    scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
-            // Add the package to the internal data structures
-            commitSuccessfulScanResults(scanResults);
-            newPackage = scanResults.get(0).pkgSetting.pkg;
-
-            // Set the update and install times
-            PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras;
-            setInstallAndUpdateTime(newPackage, deletedPkgSetting.firstInstallTime,
-                    System.currentTimeMillis());
-
-            // Update the package dynamic state if succeeded
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                // Now that the install succeeded make sure we remove data
-                // directories for any child package the update removed.
-                final int deletedChildCount = (deletedPackage.childPackages != null)
-                        ? deletedPackage.childPackages.size() : 0;
-                final int newChildCount = (newPackage.childPackages != null)
-                        ? newPackage.childPackages.size() : 0;
-                for (int i = 0; i < deletedChildCount; i++) {
-                    PackageParser.Package deletedChildPkg = deletedPackage.childPackages.get(i);
-                    boolean childPackageDeleted = true;
-                    for (int j = 0; j < newChildCount; j++) {
-                        PackageParser.Package newChildPkg = newPackage.childPackages.get(j);
-                        if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
-                            childPackageDeleted = false;
-                            break;
-                        }
-                    }
-                    if (childPackageDeleted) {
-                        PackageSetting ps = mSettings.getDisabledSystemPkgLPr(
-                                deletedChildPkg.packageName);
-                        if (ps != null && res.removedInfo.removedChildPackages != null) {
-                            PackageRemovedInfo removedChildRes = res.removedInfo
-                                    .removedChildPackages.get(deletedChildPkg.packageName);
-                            removePackageDataLIF(ps, allUsers, removedChildRes, 0, false);
-                            removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
-                        }
-                    }
-                }
-
-                updateSettingsLI(newPackage, installerPackageName, allUsers, res, user,
-                        installReason);
-                prepareAppDataAfterInstallLIF(newPackage);
-
-                mDexManager.notifyPackageUpdated(newPackage.packageName,
-                            newPackage.baseCodePath, newPackage.splitCodePaths);
-            }
-        } catch (PackageManagerException e) {
-            res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
-            res.setError("Package couldn't be installed in " + pkg.codePath, e);
-        }
-
-        if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            // Re installation failed. Restore old information
-            // Remove new pkg information
-            if (newPackage != null) {
-                removeInstalledPackageLI(newPackage, true);
-            }
-            // Add back the old system package
-            try {
-                final List<ScanResult> scanResults = scanPackageTracedLI(
-                        deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
-                commitSuccessfulScanResults(scanResults);
-            } catch (PackageManagerException e) {
-                Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
-            }
-
-            synchronized (mPackages) {
-                if (disabledSystem) {
-                    enableSystemPackageLPw(deletedPackage);
-                }
-
-                // Ensure the installer package name up to date
-                setInstallerPackageNameLPw(deletedPackage, installerPackageName);
-
-                // Update permissions for restored package
-                mPermissionManager.updatePermissions(
-                        deletedPackage.packageName, deletedPackage, false, mPackages.values(),
-                        mPermissionCallback);
-
-                mSettings.writeLPr();
-            }
-
-            Slog.i(TAG, "Successfully restored package : " + deletedPackage.packageName
-                    + " after failed upgrade");
-        }
-    }
-
     /**
      * Checks whether the parent or any of the child packages have a change shared
      * user. For a package to be a valid update the shred users of the parent and
@@ -15682,92 +14893,683 @@
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
+
     private static class InstallRequest {
-        final InstallArgs args;
-        final PackageInstalledInfo res;
+        public final InstallArgs args;
+        public final PackageInstalledInfo installResult;
 
         private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
             this.args = args;
-            this.res = res;
+            this.installResult = res;
         }
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
-    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
+    private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo installResult) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
-            installPackagesLI(Collections.singletonList(new InstallRequest(args, res)));
+            installPackagesLI(Collections.singletonList(new InstallRequest(args, installResult)));
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
+    /**
+     * Package state to commit to memory and disk after reconciliation has completed.
+     */
     private static class CommitRequest {
         final Map<String, ReconciledPackage> reconciledPackages;
+        final int[] mAllUsers;
 
-        private CommitRequest(Map<String, ReconciledPackage> reconciledPackages) {
+        private CommitRequest(Map<String, ReconciledPackage> reconciledPackages, int[] allUsers) {
             this.reconciledPackages = reconciledPackages;
+            this.mAllUsers = allUsers;
         }
     }
-    private static class ReconcileRequest {
-        final Map<String, ScanResult> scannedPackages;
 
-        private ReconcileRequest(Map<String, ScanResult> scannedPackages) {
+    /**
+     * Package scan results and related request details used to reconcile the potential addition of
+     * one or more packages to the system.
+     *
+     * Reconcile will take a set of package details that need to be committed to the system and make
+     * sure that they are valid in the context of the system and the other installing apps. Any
+     * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+     * as install) led to the request.
+     */
+    private static class ReconcileRequest {
+        public final Map<String, ScanResult> scannedPackages;
+
+        // TODO: Remove install-specific details from reconcile request; make them generic types
+        //       that can be used for scanDir for example.
+        public final Map<String, InstallArgs> installArgs;
+        public final Map<String, PackageInstalledInfo> installResults;
+        public final Map<String, PrepareResult> preparedPackages;
+
+        private ReconcileRequest(Map<String, ScanResult> scannedPackages,
+                Map<String, InstallArgs> installArgs,
+                Map<String, PackageInstalledInfo> installResults,
+                Map<String, PrepareResult> preparedPackages) {
             this.scannedPackages = scannedPackages;
+            this.installArgs = installArgs;
+            this.installResults = installResults;
+            this.preparedPackages = preparedPackages;
         }
     }
     private static class ReconcileFailure extends PackageManagerException {
         public ReconcileFailure(String message) {
             super("Invalid reconcile request: " + message);
         }
-    };
+    }
 
     /**
      * A container of all data needed to commit a package to in-memory data structures and to disk.
-     * Ideally most of the data contained in this class will move into a PackageSetting it contains.
+     * TODO: move most of the data contained her into a PackageSetting for commit.
      */
-    private static class ReconciledPackage {}
+    private static class ReconciledPackage {
+        public final PackageSetting pkgSetting;
+        public final ScanResult scanResult;
+        public final UserHandle installForUser;
+        public final String volumeUuid;
+        // TODO: Remove install-specific details from the reconcile result
+        public final PackageInstalledInfo installResult;
+        public final PrepareResult prepareResult;
+        @PackageManager.InstallFlags
+        public final int installFlags;
+        public final InstallArgs installArgs;
+
+        private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
+                UserHandle installForUser, PackageInstalledInfo installResult, int installFlags,
+                String volumeUuid, PrepareResult prepareResult, ScanResult scanResult) {
+            this.installArgs = installArgs;
+            this.pkgSetting = pkgSetting;
+            this.installForUser = installForUser;
+            this.installResult = installResult;
+            this.installFlags = installFlags;
+            this.volumeUuid = volumeUuid;
+            this.prepareResult = prepareResult;
+            this.scanResult = scanResult;
+        }
+    }
 
     @GuardedBy("mPackages")
     private static Map<String, ReconciledPackage> reconcilePackagesLocked(
-            final ReconcileRequest request) throws ReconcileFailure {
-        return Collections.emptyMap();
+            final ReconcileRequest request)
+            throws ReconcileFailure {
+        Map<String, ReconciledPackage> result = new ArrayMap<>(request.scannedPackages.size());
+        for (String installPackageName : request.installArgs.keySet()) {
+            final ScanResult scanResult = request.scannedPackages.get(installPackageName);
+            final InstallArgs installArgs = request.installArgs.get(installPackageName);
+            final PackageInstalledInfo res = request.installResults.get(installPackageName);
+            if (scanResult == null || installArgs == null || res == null) {
+                throw new ReconcileFailure(
+                        "inputs not balanced; missing argument for " + installPackageName);
+            }
+            result.put(installPackageName,
+                    new ReconciledPackage(installArgs, scanResult.pkgSetting, installArgs.getUser(),
+                            res, installArgs.installFlags, installArgs.volumeUuid,
+                            request.preparedPackages.get(installPackageName), scanResult));
+        }
+        return result;
     }
 
     @GuardedBy("mPackages")
     private boolean commitPackagesLocked(final CommitRequest request) {
+        // TODO: remove any expected failures from this method; this should only be able to fail due
+        //       to unavoidable errors (I/O, etc.)
+        for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
+            final ScanResult scanResult = reconciledPkg.scanResult;
+            final ScanRequest scanRequest = scanResult.request;
+            final PackageParser.Package pkg = scanRequest.pkg;
+            final String packageName = pkg.packageName;
+            final PackageInstalledInfo res = reconciledPkg.installResult;
+
+            if (reconciledPkg.prepareResult.replace) {
+                PackageParser.Package oldPackage = mPackages.get(packageName);
+                if (reconciledPkg.prepareResult.system) {
+                    // Remove existing system package
+                    removePackageLI(oldPackage, true);
+                    if (!disableSystemPackageLPw(oldPackage, pkg)) {
+                        // We didn't need to disable the .apk as a current system package,
+                        // which means we are replacing another update that is already
+                        // installed.  We need to make sure to delete the older one's .apk.
+                        res.removedInfo.args = createInstallArgsForExisting(0,
+                                oldPackage.applicationInfo.getCodePath(),
+                                oldPackage.applicationInfo.getResourcePath(),
+                                getAppDexInstructionSets(oldPackage.applicationInfo));
+                    } else {
+                        res.removedInfo.args = null;
+                    }
+
+                    // Set the update and install times
+                    PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+                    setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+                            System.currentTimeMillis());
+
+                    // Update the package dynamic state if succeeded
+                    // Now that the install succeeded make sure we remove data
+                    // directories for any child package the update removed.
+                    final int deletedChildCount = (oldPackage.childPackages != null)
+                            ? oldPackage.childPackages.size() : 0;
+                    final int newChildCount = (pkg.childPackages != null)
+                            ? pkg.childPackages.size() : 0;
+                    for (int i = 0; i < deletedChildCount; i++) {
+                        PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
+                        boolean childPackageDeleted = true;
+                        for (int j = 0; j < newChildCount; j++) {
+                            PackageParser.Package newChildPkg = pkg.childPackages.get(j);
+                            if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
+                                childPackageDeleted = false;
+                                break;
+                            }
+                        }
+                        if (childPackageDeleted) {
+                            PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
+                                    deletedChildPkg.packageName);
+                            if (ps1 != null && res.removedInfo.removedChildPackages != null) {
+                                PackageRemovedInfo removedChildRes = res.removedInfo
+                                        .removedChildPackages.get(deletedChildPkg.packageName);
+                                removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
+                                        false);
+                                removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
+                                        == null;
+                            }
+                        }
+                    }
+                } else {
+                    final boolean killApp = (scanRequest.scanFlags & SCAN_DONT_KILL_APP) == 0;
+                    final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+                            | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
+                    // First delete the existing package while retaining the data directory
+                    if (!deletePackageLIF(packageName, null, true, request.mAllUsers, deleteFlags,
+                            res.removedInfo, true, pkg)) {
+                        // If the existing package wasn't successfully deleted
+                        res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
+                                "replaceNonSystemPackageLI");
+                        return false;
+                    } else {
+                        // Successfully deleted the old package; proceed with replace.
+
+                        // If deleted package lived in a container, give users a chance to
+                        // relinquish resources before killing.
+                        if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+                            if (DEBUG_INSTALL) {
+                                Slog.i(TAG, "upgrading pkg " + oldPackage
+                                        + " is ASEC-hosted -> UNAVAILABLE");
+                            }
+                            final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+                            final ArrayList<String> pkgList = new ArrayList<>(1);
+                            pkgList.add(oldPackage.applicationInfo.packageName);
+                            sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+                        }
+
+                        clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
+                                | StorageManager.FLAG_STORAGE_CE
+                                | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+                    }
+
+
+
+                    // Update the in-memory copy of the previous code paths.
+                    PackageSetting ps1 = mSettings.mPackages.get(
+                            reconciledPkg.prepareResult.existingPackage.packageName);
+                    if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
+                            == 0) {
+                        if (ps1.mOldCodePaths == null) {
+                            ps1.mOldCodePaths = new ArraySet<>();
+                        }
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
+                        if (oldPackage.splitCodePaths != null) {
+                            Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+                        }
+                    } else {
+                        ps1.mOldCodePaths = null;
+                    }
+                    if (ps1.childPackageNames != null) {
+                        for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
+                            final String childPkgName = ps1.childPackageNames.get(i);
+                            final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+                            childPs.mOldCodePaths = ps1.mOldCodePaths;
+                        }
+                    }
+
+                    if (reconciledPkg.installResult.returnCode
+                            == PackageManager.INSTALL_SUCCEEDED) {
+                        PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+                        if (ps2 != null) {
+                            res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
+                            if (res.removedInfo.removedChildPackages != null) {
+                                final int childCount1 = res.removedInfo.removedChildPackages.size();
+                                // Iterate in reverse as we may modify the collection
+                                for (int i = childCount1 - 1; i >= 0; i--) {
+                                    String childPackageName =
+                                            res.removedInfo.removedChildPackages.keyAt(i);
+                                    if (res.addedChildPackages.containsKey(childPackageName)) {
+                                        res.removedInfo.removedChildPackages.removeAt(i);
+                                    } else {
+                                        PackageRemovedInfo childInfo = res.removedInfo
+                                                .removedChildPackages.valueAt(i);
+                                        childInfo.removedForAllUsers = mPackages.get(
+                                                childInfo.removedPackage) == null;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+
+
+            try {
+                commitScanResultLocked(scanResult);
+            } catch (PackageManagerException e) {
+                res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
+                res.setError("Package couldn't be installed in " + pkg.codePath, e);
+                return false;
+            }
+            updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers,
+                    res, reconciledPkg.installForUser, reconciledPkg.installArgs.installReason);
+
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps != null) {
+                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                ps.setUpdateAvailable(false /*updateAvailable*/);
+            }
+            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+            for (int i = 0; i < childCount; i++) {
+                PackageParser.Package childPkg = pkg.childPackages.get(i);
+                PackageInstalledInfo childRes = res.addedChildPackages.get(
+                        childPkg.packageName);
+                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
+                if (childPs != null) {
+                    childRes.newUsers = childPs.queryInstalledUsers(
+                            sUserManager.getUserIds(), true);
+                }
+            }
+            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                updateSequenceNumberLP(ps, res.newUsers);
+                updateInstantAppInstallerLocked(packageName);
+            }
+        }
         return true;
     }
 
-    @GuardedBy({"mInstallLock", "mPackages", "PackageManagerService.mPackages"})
+    /**
+     * Installs one or more packages atomically. This operation is broken up into four phases:
+     * <ul>
+     *     <li><b>Prepare</b>
+     *         <br/>Analyzes any current install state, parses the package and does initial
+     *         validation on it.</li>
+     *     <li><b>Scan</b>
+     *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
+     *     <li><b>Reconcile</b>
+     *         <br/>Validates scanned packages in the context of each other and the current system
+     *         state to ensure that the install will be successful.
+     *     <li><b>Commit</b>
+     *         <br/>Commits all scanned packages and updates system state. This is the only place
+     *         that system state may be modified in the install flow and all predictable errors
+     *         must be determined before this phase.</li>
+     * </ul>
+     *
+     * Failure at any phase will result in a full failure to install all packages.
+     */
+    @GuardedBy({"mInstallLock", "mPackages"})
     private void installPackagesLI(List<InstallRequest> requests) {
-        Map<String, ScanResult> scans = new ArrayMap<>(requests.size());
-        for (InstallRequest request : requests) {
-            // TODO(b/109941548): remove this once we've pulled everything from it and into scan,
-            // reconcile or commit.
-            preparePackageLI(request.args, request.res);
-
-            // TODO(b/109941548): scan package and get result
-        }
-        ReconcileRequest reconcileRequest = new ReconcileRequest(scans);
-        Map<String, ReconciledPackage> reconciledPackages;
+        final Map<String, ScanResult> scans = new ArrayMap<>(requests.size());
+        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
+        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
+        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
         try {
-            reconciledPackages = reconcilePackagesLocked(reconcileRequest);
-        } catch (ReconcileFailure e) {
-            // TODO(b/109941548): set install args error
-            return;
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
+            for (InstallRequest request : requests) {
+                // TODO(b/109941548): remove this once we've pulled everything from it and into
+                //                    scan, reconcile or commit.
+                final PrepareResult prepareResult;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
+                    prepareResult = preparePackageLI(request.args, request.installResult);
+                } catch (PrepareFailure prepareFailure) {
+                    request.installResult.setError(prepareFailure.error,
+                            prepareFailure.getMessage());
+                    request.installResult.origPackage = prepareFailure.conflictingPackage;
+                    request.installResult.origPermission = prepareFailure.conflictingPermission;
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                request.installResult.installerPackageName = request.args.installerPackageName;
+
+                final String packageName = prepareResult.packageToScan.packageName;
+                prepareResults.put(packageName, prepareResult);
+                installResults.put(packageName, request.installResult);
+                installArgs.put(packageName, request.args);
+                try {
+                    final List<ScanResult> scanResults = scanPackageTracedLI(
+                            prepareResult.packageToScan, prepareResult.parseFlags,
+                            prepareResult.scanFlags, System.currentTimeMillis(),
+                            request.args.user);
+                    for (ScanResult result : scanResults) {
+                        if (null != scans.put(result.pkgSetting.pkg.packageName, result)) {
+                            request.installResult.setError(
+                                    PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                    "Duplicate package " + result.pkgSetting.pkg.packageName
+                                            + " in atomic install request.");
+                            return;
+                        }
+                    }
+                } catch (PackageManagerException e) {
+                    request.installResult.setError("Scanning Failed.", e);
+                    return;
+                }
+            }
+            ReconcileRequest reconcileRequest = new ReconcileRequest(scans, installArgs,
+                    installResults,
+                    prepareResults);
+            CommitRequest commitRequest = null;
+            synchronized (mPackages) {
+                Map<String, ReconciledPackage> reconciledPackages;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
+                    reconciledPackages = reconcilePackagesLocked(reconcileRequest);
+                } catch (ReconcileFailure e) {
+                    for (InstallRequest request : requests) {
+                        // TODO(b/109941548): add more concrete failure reasons
+                        request.installResult.setError("Reconciliation failed...", e);
+                        // TODO: return any used system resources
+                    }
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
+                    commitRequest = new CommitRequest(reconciledPackages,
+                            sUserManager.getUserIds());
+                    if (!commitPackagesLocked(commitRequest)) {
+                        cleanUpCommitFailuresLocked(commitRequest);
+                        return;
+                    }
+                } finally {
+                    for (PrepareResult result : prepareResults.values()) {
+                        if (result.freezer != null) {
+                            result.freezer.close();
+                        }
+                    }
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            }
+            executePostCommitSteps(commitRequest);
+        } finally {
+            for (PrepareResult result : prepareResults.values()) {
+                if (result.freezer != null) {
+                    result.freezer.close();
+                }
+            }
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-        CommitRequest request = new CommitRequest(reconciledPackages);
-        if (!commitPackagesLocked(request)) {
-            // TODO(b/109941548): set install args error
-            return;
-        }
-        // TODO(b/109941548) post-commit actions (dex-opt, etc.)
     }
 
-    @Deprecated
+    /**
+     * On successful install, executes remaining steps after commit completes and the package lock
+     * is released.
+     */
+    private void executePostCommitSteps(CommitRequest commitRequest) {
+        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
+            final boolean forwardLocked =
+                    ((reconciledPkg.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+            final boolean instantApp =
+                    ((reconciledPkg.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
+            final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
+            final String packageName = pkg.packageName;
+            prepareAppDataAfterInstallLIF(pkg);
+            if (reconciledPkg.prepareResult.clearCodeCache) {
+                clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
+                        | StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            }
+            if (reconciledPkg.prepareResult.replace) {
+                mDexManager.notifyPackageUpdated(pkg.packageName,
+                        pkg.baseCodePath, pkg.splitCodePaths);
+            }
+
+            // Prepare the application profiles for the new code paths.
+            // This needs to be done before invoking dexopt so that any install-time profile
+            // can be used for optimizations.
+            mArtManagerService.prepareAppProfiles(
+                    pkg, resolveUserIds(reconciledPkg.installForUser.getIdentifier()));
+
+            // Check whether we need to dexopt the app.
+            //
+            // NOTE: it is IMPORTANT to call dexopt:
+            //   - after doRename which will sync the package data from PackageParser.Package and
+            //     its corresponding ApplicationInfo.
+            //   - after installNewPackageLIF or replacePackageLIF which will update result with the
+            //     uid of the application (pkg.applicationInfo.uid).
+            //     This update happens in place!
+            //
+            // We only need to dexopt if the package meets ALL of the following conditions:
+            //   1) it is not forward locked.
+            //   2) it is not on on an external ASEC container.
+            //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
+            //   4) it is not debuggable.
+            //
+            // Note that we do not dexopt instant apps by default. dexopt can take some time to
+            // complete, so we skip this step during installation. Instead, we'll take extra time
+            // the first time the instant app starts. It's preferred to do it this way to provide
+            // continuous progress to the useur instead of mysteriously blocking somewhere in the
+            // middle of running an instant app. The default behaviour can be overridden
+            // via gservices.
+            final boolean performDexopt = !forwardLocked
+                    && !pkg.applicationInfo.isExternalAsec()
+                    && (!instantApp || Global.getInt(mContext.getContentResolver(),
+                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
+                    && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+
+            if (performDexopt) {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+                // Do not run PackageDexOptimizer through the local performDexOpt
+                // method because `pkg` may not be in `mPackages` yet.
+                //
+                // Also, don't fail application installs if the dexopt step fails.
+                DexoptOptions dexoptOptions = new DexoptOptions(packageName,
+                        REASON_INSTALL,
+                        DexoptOptions.DEXOPT_BOOT_COMPLETE
+                                | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
+                mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+                        null /* instructionSets */,
+                        getOrCreateCompilerPackageStats(pkg),
+                        mDexManager.getPackageUseInfoOrDefault(packageName),
+                        dexoptOptions);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
+
+            // Notify BackgroundDexOptService that the package has been changed.
+            // If this is an update of a package which used to fail to compile,
+            // BackgroundDexOptService will remove it from its blacklist.
+            // TODO: Layering violation
+            BackgroundDexOptService.notifyPackageChanged(packageName);
+        }
+
+    }
+
+    private void cleanUpCommitFailuresLocked(CommitRequest request) {
+        final Map<String, ReconciledPackage> reconciledPackages = request.reconciledPackages;
+        final int[] allUsers = request.mAllUsers;
+        for (ReconciledPackage reconciledPackage : reconciledPackages.values()) {
+            final String pkgName1 = reconciledPackage.pkgSetting.pkg.packageName;
+            if (reconciledPackage.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                reconciledPackage.installResult.setError(
+                        PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "Commit failed...");
+            }
+            final PackageParser.Package oldPackage =
+                    reconciledPackage.prepareResult.existingPackage;
+            final PackageParser.Package newPackage = reconciledPackage.pkgSetting.pkg;
+            if (reconciledPackage.prepareResult.system) {
+                // Re installation failed. Restore old information
+                // Remove new pkg information
+                if (newPackage != null) {
+                    removeInstalledPackageLI(newPackage, true);
+                }
+                // Add back the old system package
+                PackageParser.Package restoredPkg = null;
+                try {
+                    final List<ScanResult> restoreResults = scanPackageTracedLI(oldPackage,
+                            reconciledPackage.prepareResult.parseFlags, SCAN_UPDATE_SIGNATURE, 0,
+                            reconciledPackage.installForUser);
+                    commitSuccessfulScanResults(restoreResults);
+                    restoredPkg = restoreResults.get(0).pkgSetting.pkg;
+                } catch (PackageManagerException e) {
+                    Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
+                }
+                synchronized (mPackages) {
+                    final boolean disabledSystem;
+                    // Remove existing system package
+                    removePackageLI(reconciledPackage.scanResult.pkgSetting.pkg, true);
+                    disabledSystem = disableSystemPackageLPw(
+                            reconciledPackage.scanResult.pkgSetting.pkg, restoredPkg);
+                    if (disabledSystem) {
+                        enableSystemPackageLPw(restoredPkg);
+                    }
+                    // Ensure the installer package name up to date
+                    setInstallerPackageNameLPw(reconciledPackage.scanResult.pkgSetting.pkg,
+                            reconciledPackage.installArgs.installerPackageName);
+                    // Update permissions for restored package
+                    mPermissionManager.updatePermissions(
+                            restoredPkg.packageName, restoredPkg, false, mPackages.values(),
+                            mPermissionCallback);
+                    mSettings.writeLPr();
+                }
+                Slog.i(TAG, "Successfully restored package : " + restoredPkg.packageName
+                        + " after failed upgrade");
+            } else if (reconciledPackage.prepareResult.replace) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName1);
+
+                // Revert all internal state mutations and added folders for the failed install
+                boolean deletedPkg = deletePackageLIF(pkgName1, null, true,
+                        allUsers, /*TODO: deleteFlags*/ 0,
+                        reconciledPackage.installResult.removedInfo, true, null);
+
+                // Restore the old package
+                if (deletedPkg) {
+                    if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + oldPackage);
+                    File restoreFile = new File(oldPackage.codePath);
+                    // Parse old package
+                    boolean oldExternal = isExternal(oldPackage);
+                    int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+                            | (oldPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0)
+                            | (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
+                    int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
+                    try {
+                        scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags,
+                                /* origUpdateTime */ System.currentTimeMillis(), null);
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "Failed to restore package : " + pkgName1
+                                + " after failed upgrade: "
+                                + e.getMessage());
+                        return;
+                    }
+
+                    synchronized (mPackages) {
+                        // Ensure the installer package name up to date
+                        setInstallerPackageNameLPw(oldPackage,
+                                reconciledPackage.installArgs.installerPackageName);
+
+                        // Update permissions for restored package
+                        mPermissionManager.updatePermissions(
+                                oldPackage.packageName, oldPackage, false, mPackages.values(),
+                                mPermissionCallback);
+
+                        mSettings.writeLPr();
+                    }
+
+                    Slog.i(TAG, "Successfully restored package : " + pkgName1
+                            + " after failed upgrade");
+                }
+            } else {
+                // Remove package from internal structures, but keep around any
+                // data that might have already existed
+                deletePackageLIF(pkgName1, UserHandle.ALL, false, null,
+                        PackageManager.DELETE_KEEP_DATA,
+                        reconciledPackage.installResult.removedInfo, true, null);
+            }
+        }
+    }
+
+    /**
+     * The set of data needed to successfully install the prepared package. This includes data that
+     * will be used to scan and reconcile the package.
+     */
+    private static class PrepareResult {
+        public final int installReason;
+        public final String volumeUuid;
+        public final String installerPackageName;
+        public final UserHandle user;
+        public final boolean replace;
+        public final int scanFlags;
+        public final int parseFlags;
+        @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+        public final PackageParser.Package existingPackage;
+        public final PackageParser.Package packageToScan;
+        public final boolean clearCodeCache;
+        public final boolean system;
+        /* The original package name if it was changed during an update, otherwise {@code null}. */
+        @Nullable
+        public final String renamedPackage;
+        public final PackageFreezer freezer;
+
+        private PrepareResult(int installReason, String volumeUuid,
+                String installerPackageName, UserHandle user, boolean replace, int scanFlags,
+                int parseFlags, PackageParser.Package existingPackage,
+                PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
+                String renamedPackage,
+                PackageFreezer freezer) {
+            this.installReason = installReason;
+            this.volumeUuid = volumeUuid;
+            this.installerPackageName = installerPackageName;
+            this.user = user;
+            this.replace = replace;
+            this.scanFlags = scanFlags;
+            this.parseFlags = parseFlags;
+            this.existingPackage = existingPackage;
+            this.packageToScan = packageToScan;
+            this.clearCodeCache = clearCodeCache;
+            this.system = system;
+            this.renamedPackage = renamedPackage;
+            this.freezer = freezer;
+        }
+    }
+
+    private static class PrepareFailure extends PackageManagerException {
+
+        public String conflictingPackage;
+        public String conflictingPermission;
+
+        PrepareFailure(int error) {
+            super(error, "Failed to prepare for install.");
+        }
+
+        PrepareFailure(int error, String detailMessage) {
+            super(error, detailMessage);
+        }
+
+        PrepareFailure(String message, Exception e) {
+            super(e instanceof PackageParserException
+                    ? ((PackageParserException) e).error
+                    : ((PackageManagerException) e).error,
+                    ExceptionUtils.getCompleteMessage(message, e));
+        }
+
+        PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
+                String conflictingPackage) {
+            this.conflictingPermission = conflictingPermission;
+            this.conflictingPackage = conflictingPackage;
+            return this;
+        }
+    }
+
     @GuardedBy("mInstallLock")
-    private void preparePackageLI(InstallArgs args, PackageInstalledInfo res) {
+    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
+            throws PrepareFailure {
         final int installFlags = args.installFlags;
         final String installerPackageName = args.installerPackageName;
         final String volumeUuid = args.volumeUuid;
@@ -15780,7 +15582,6 @@
         final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
         final boolean virtualPreload =
                 ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-        boolean replace = false;
         @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
         if (args.move != null) {
             // moving a complete application; perform an initial scan on the new install location
@@ -15799,18 +15600,13 @@
             scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
         }
 
-        // Result object to be returned
-        res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-        res.installerPackageName = installerPackageName;
-
         if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
 
         // Sanity check
         if (instantApp && (forwardLocked || onExternal)) {
             Slog.i(TAG, "Incompatible ephemeral install; fwdLocked=" + forwardLocked
                     + " external=" + onExternal);
-            res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
-            return;
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
         }
 
         // Retrieve PackageSettings and parse package
@@ -15819,6 +15615,7 @@
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                 | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
                 | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
+
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
         pp.setDisplayMetrics(mMetrics);
@@ -15830,8 +15627,7 @@
             pkg = pp.parsePackage(tmpPackageFile, parseFlags);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
-            res.setError("Failed parse during installPackageLI", e);
-            return;
+            throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -15841,16 +15637,14 @@
             if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
                 Slog.w(TAG,
                         "Instant app package " + pkg.packageName + " does not target at least O");
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package must target at least O");
-                return;
             }
             if (pkg.mSharedUserId != null) {
                 Slog.w(TAG, "Instant app package " + pkg.packageName
                         + " may not declare sharedUserId.");
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package may not declare a sharedUserId");
-                return;
             }
         }
 
@@ -15861,9 +15655,8 @@
             // No static shared libs on external storage
             if (onExternal) {
                 Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
-                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                         "Packages declaring static-shared libs cannot be updated");
-                return;
             }
         }
 
@@ -15902,10 +15695,9 @@
         }
 
         String pkgName = res.name = pkg.packageName;
-        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
-                res.setError(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
-                return;
+                throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
             }
         }
 
@@ -15917,22 +15709,21 @@
                 PackageParser.collectCertificates(pkg, false /* skipVerify */);
             }
         } catch (PackageParserException e) {
-            res.setError("Failed collect during installPackageLI", e);
-            return;
+            throw new PrepareFailure("Failed collect during installPackageLI", e);
         }
 
         if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
                 < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
             Slog.w(TAG, "Instant app package " + pkg.packageName
                     + " is not signed with at least APK Signature Scheme v2");
-            res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+            throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                     "Instant app package must be signed with APK Signature Scheme v2 or greater");
-            return;
         }
 
         // Get rid of all references to package scan path via parser.
         pp = null;
         boolean systemApp = false;
+        boolean replace = false;
         synchronized (mPackages) {
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
@@ -15947,8 +15738,10 @@
                     pkg.setPackageName(oldName);
                     pkgName = pkg.packageName;
                     replace = true;
-                    if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
-                            + oldName + " pkgName=" + pkgName);
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Replacing existing renamed package: oldName="
+                                + oldName + " pkgName=" + pkgName);
+                    }
                 } else if (mPackages.containsKey(pkgName)) {
                     // This package, under its official name, already exists
                     // on the device; we should replace it.
@@ -15958,11 +15751,11 @@
 
                 // Child packages are installed through the parent package
                 if (pkg.parentPackage != null) {
-                    res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                    throw new PrepareFailure(
+                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                             "Package " + pkg.packageName + " is child of package "
                                     + pkg.parentPackage.parentPackage + ". Child packages "
                                     + "can be updated only through the parent package.");
-                    return;
                 }
 
                 if (replace) {
@@ -15972,26 +15765,25 @@
                     final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
                     if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                             && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
                                 "Package " + pkg.packageName + " new target SDK " + newTargetSdk
                                         + " doesn't support runtime permissions but the old"
                                         + " target SDK " + oldTargetSdk + " does.");
-                        return;
                     }
                     // Prevent persistent apps from being updated
                     if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) {
-                        res.setError(PackageManager.INSTALL_FAILED_INVALID_APK,
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
                                 "Package " + oldPackage.packageName + " is a persistent app. "
                                         + "Persistent apps are not updateable.");
-                        return;
                     }
                     // Prevent installing of child packages
                     if (oldPackage.parentPackage != null) {
-                        res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
                                 "Package " + pkg.packageName + " is child of package "
                                         + oldPackage.parentPackage + ". Child packages "
                                         + "can be updated only through the parent package.");
-                        return;
                     }
                 }
             }
@@ -16018,10 +15810,9 @@
                 final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                 if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                     if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
-                        res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                 + pkg.packageName + " upgrade keys do not match the "
                                 + "previously installed version");
-                        return;
                     }
                 } else {
                     try {
@@ -16038,8 +15829,7 @@
                             }
                         }
                     } catch (PackageManagerException e) {
-                        res.setError(e.error, e.getMessage());
-                        return;
+                        throw new PrepareFailure(e.error, e.getMessage());
                     }
                 }
 
@@ -16050,8 +15840,9 @@
                 res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
             }
 
+
             int N = pkg.permissions.size();
-            for (int i = N-1; i >= 0; i--) {
+            for (int i = N - 1; i >= 0; i--) {
                 final PackageParser.Permission perm = pkg.permissions.get(i);
                 final BasePermission bp =
                         (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
@@ -16076,7 +15867,7 @@
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                     if (sourcePackageName.equals(pkg.packageName)
                             && (ksms.shouldCheckUpgradeKeySetLocked(
-                                    sourcePackageSetting, scanFlags))) {
+                            sourcePackageSetting, scanFlags))) {
                         sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
                     } else {
 
@@ -16084,12 +15875,12 @@
                         // package's certificate has rotated from the current one, or if it is an
                         // older certificate with which the current is ok with sharing permissions
                         if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
-                                        pkg.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                                pkg.mSigningDetails,
+                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                             sigsOk = true;
                         } else if (pkg.mSigningDetails.checkCapability(
-                                        sourcePackageSetting.signatures.mSigningDetails,
-                                        PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
+                                sourcePackageSetting.signatures.mSigningDetails,
+                                PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
 
                             // the scanned package checks out, has signing certificate rotation
                             // history, and is newer; bring it over
@@ -16104,12 +15895,13 @@
                         // install to proceed; we fail the install on all other permission
                         // redefinitions.
                         if (!sourcePackageName.equals("android")) {
-                            res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
-                                    + pkg.packageName + " attempting to redeclare permission "
-                                    + perm.info.name + " already owned by " + sourcePackageName);
-                            res.origPermission = perm.info.name;
-                            res.origPackage = sourcePackageName;
-                            return;
+                            throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
+                                    + pkg.packageName
+                                    + " attempting to redeclare permission "
+                                    + perm.info.name + " already owned by "
+                                    + sourcePackageName)
+                                    .conflictsWithExistingPermission(perm.info.name,
+                                            sourcePackageName);
                         } else {
                             Slog.w(TAG, "Package " + pkg.packageName
                                     + " attempting to redeclare system permission "
@@ -16138,14 +15930,12 @@
         if (systemApp) {
             if (onExternal) {
                 // Abort update; system app can't be replaced with app on sdcard
-                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                         "Cannot install updates to system apps on sdcard");
-                return;
             } else if (instantApp) {
                 // Abort update; system app can't be replaced with an instant app
-                res.setError(INSTALL_FAILED_INSTANT_APP_INVALID,
+                throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Cannot update a system app with an instant app");
-                return;
             }
         }
 
@@ -16173,13 +15963,13 @@
 
             try {
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
-                    args.abiOverride : pkg.cpuAbiOverride);
+                        args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
                 derivePackageAbi(pkg, abiOverride, extractNativeLibs);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
-                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
-                return;
+                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Error deriving application ABI");
             }
 
             // Shared libraries for the package need to be updated.
@@ -16193,8 +15983,7 @@
         }
 
         if (!args.doRename(res.returnCode, pkg)) {
-            res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
-            return;
+            throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
         }
 
         if (PackageManagerServiceUtils.isApkVerityEnabled()) {
@@ -16208,7 +15997,6 @@
                     apkPath = pkg.baseCodePath;
                 }
             }
-
             if (apkPath != null) {
                 final VerityUtils.SetupResult result =
                         VerityUtils.generateApkVeritySetupData(apkPath);
@@ -16220,16 +16008,15 @@
                         mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
                         mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
                     } catch (InstallerException | IOException | DigestException |
-                             NoSuchAlgorithmException e) {
-                        res.setError(INSTALL_FAILED_INTERNAL_ERROR,
+                            NoSuchAlgorithmException e) {
+                        throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                                 "Failed to set up verity: " + e);
-                        return;
                     } finally {
                         IoUtils.closeQuietly(fd);
                     }
                 } else if (result.isFailed()) {
-                    res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Failed to generate verity");
-                    return;
+                    throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Failed to generate verity");
                 } else {
                     // Do nothing if verity is skipped. Will fall back to full apk verification on
                     // reboot.
@@ -16244,109 +16031,293 @@
                 Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
             }
         }
+        final PackageFreezer freezer =
+                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
+        boolean shouldCloseFreezerBeforeReturn = true;
+        try {
+            final PackageParser.Package existingPackage;
+            String renamedPackage = null;
+            boolean clearCodeCache = false;
+            boolean sysPkg = false;
+            String targetVolumeUuid = volumeUuid;
+            int targetScanFlags = scanFlags;
+            int targetParseFlags = parseFlags;
 
-        try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
-                "installPackageLI")) {
             if (replace) {
+                targetVolumeUuid = null;
                 if (pkg.applicationInfo.isStaticSharedLibrary()) {
                     // Static libs have a synthetic package name containing the version
                     // and cannot be updated as an update would get a new package name,
                     // unless this is the exact same version code which is useful for
                     // development.
                     PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
-                    if (existingPkg != null &&
-                            existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
-                        res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
-                                + "static-shared libs cannot be updated");
-                        return;
+                    if (existingPkg != null
+                            && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Packages declaring "
+                                        + "static-shared libs cannot be updated");
                     }
                 }
-                replacePackageLIF(pkg, parseFlags, scanFlags, args.user,
-                        installerPackageName, res, args.installReason);
-            } else {
-                installNewPackageLIF(pkg, parseFlags, scanFlags,
-                        args.user, installerPackageName, volumeUuid, res, args.installReason);
-            }
-        }
 
-        // Prepare the application profiles for the new code paths.
-        // This needs to be done before invoking dexopt so that any install-time profile
-        // can be used for optimizations.
-        mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
+                final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
 
-        // Check whether we need to dexopt the app.
-        //
-        // NOTE: it is IMPORTANT to call dexopt:
-        //   - after doRename which will sync the package data from PackageParser.Package and its
-        //     corresponding ApplicationInfo.
-        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
-        //     uid of the application (pkg.applicationInfo.uid).
-        //     This update happens in place!
-        //
-        // We only need to dexopt if the package meets ALL of the following conditions:
-        //   1) it is not forward locked.
-        //   2) it is not on on an external ASEC container.
-        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
-        //   4) it is not debuggable.
-        //
-        // Note that we do not dexopt instant apps by default. dexopt can take some time to
-        // complete, so we skip this step during installation. Instead, we'll take extra time
-        // the first time the instant app starts. It's preferred to do it this way to provide
-        // continuous progress to the useur instead of mysteriously blocking somewhere in the
-        // middle of running an instant app. The default behaviour can be overridden
-        // via gservices.
-        final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
-                && !forwardLocked
-                && !pkg.applicationInfo.isExternalAsec()
-                && (!instantApp || Global.getInt(mContext.getContentResolver(),
-                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+                final PackageParser.Package oldPackage;
+                final PackageSetting ps;
+                final String pkgName11 = pkg.packageName;
+                final int[] allUsers;
+                final int[] installedUsers;
 
-        if (performDexopt) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-            // Do not run PackageDexOptimizer through the local performDexOpt
-            // method because `pkg` may not be in `mPackages` yet.
-            //
-            // Also, don't fail application installs if the dexopt step fails.
-            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
-                    REASON_INSTALL,
-                    DexoptOptions.DEXOPT_BOOT_COMPLETE |
-                    DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
-            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
-                    null /* instructionSets */,
-                    getOrCreateCompilerPackageStats(pkg),
-                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
-                    dexoptOptions);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
+                synchronized (mPackages) {
+                    oldPackage = mPackages.get(pkgName11);
+                    existingPackage = oldPackage;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+                    }
 
-        // Notify BackgroundDexOptService that the package has been changed.
-        // If this is an update of a package which used to fail to compile,
-        // BackgroundDexOptService will remove it from its blacklist.
-        // TODO: Layering violation
-        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+                    // don't allow upgrade to target a release SDK from a pre-release SDK
+                    final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
+                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
+                    final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
+                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
+                    if (oldTargetsPreRelease
+                            && !newTargetsPreRelease
+                            && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
+                        Slog.w(TAG, "Can't install package targeting released sdk");
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
+                    }
 
-        synchronized (mPackages) {
-            final PackageSetting ps = mSettings.mPackages.get(pkgName);
-            if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
-                ps.setUpdateAvailable(false /*updateAvailable*/);
-            }
+                    ps = mSettings.mPackages.get(pkgName11);
 
-            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
-                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                if (childPs != null) {
-                    childRes.newUsers = childPs.queryInstalledUsers(
-                            sUserManager.getUserIds(), true);
+                    // verify signatures are valid
+                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                    if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+                        if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                    "New package not signed by keys specified by upgrade-keysets: "
+                                            + pkgName11);
+                        }
+                    } else {
+                        // default to original signature matching
+                        if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+                                SigningDetails.CertCapabilities.INSTALLED_DATA)
+                                && !oldPackage.mSigningDetails.checkCapability(
+                                pkg.mSigningDetails,
+                                SigningDetails.CertCapabilities.ROLLBACK)) {
+                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                    "New package has a different signature: " + pkgName11);
+                        }
+                    }
+
+                    // don't allow a system upgrade unless the upgrade hash matches
+                    if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+                        final byte[] digestBytes;
+                        try {
+                            final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+                            updateDigest(digest, new File(pkg.baseCodePath));
+                            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+                                for (String path : pkg.splitCodePaths) {
+                                    updateDigest(digest, new File(path));
+                                }
+                            }
+                            digestBytes = digest.digest();
+                        } catch (NoSuchAlgorithmException | IOException e) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "Could not compute hash: " + pkgName11);
+                        }
+                        if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "New package fails restrict-update check: " + pkgName11);
+                        }
+                        // retain upgrade restriction
+                        pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+                    }
+
+                    // Check for shared user id changes
+                    String invalidPackageName =
+                            getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+                    if (invalidPackageName != null) {
+                        throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+                                "Package " + invalidPackageName + " tried to change user "
+                                        + oldPackage.mSharedUserId);
+                    }
+
+                    // check if the new package supports all of the abis which the old package
+                    // supports
+                    boolean oldPkgSupportMultiArch =
+                            oldPackage.applicationInfo.secondaryCpuAbi != null;
+                    boolean newPkgSupportMultiArch = pkg.applicationInfo.secondaryCpuAbi != null;
+                    if (isSystemApp(oldPackage) && oldPkgSupportMultiArch
+                            && !newPkgSupportMultiArch) {
+                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                "Update to package " + pkgName11 + " doesn't support multi arch");
+                    }
+
+                    // In case of rollback, remember per-user/profile install state
+                    allUsers = sUserManager.getUserIds();
+                    installedUsers = ps.queryInstalledUsers(allUsers, true);
+
+
+                    // don't allow an upgrade from full to ephemeral
+                    if (isInstantApp) {
+                        if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
+                            for (int currentUser : allUsers) {
+                                if (!ps.getInstantApp(currentUser)) {
+                                    // can't downgrade from full to instant
+                                    Slog.w(TAG,
+                                            "Can't replace full app with instant app: " + pkgName11
+                                                    + " for user: " + currentUser);
+                                    throw new PrepareFailure(
+                                            PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+                                }
+                            }
+                        } else if (!ps.getInstantApp(args.user.getIdentifier())) {
+                            // can't downgrade from full to instant
+                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
+                                    + " for user: " + args.user.getIdentifier());
+                            throw new PrepareFailure(
+                                    PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+                        }
+                    }
+                }
+
+                // Update what is removed
+                res.removedInfo = new PackageRemovedInfo(this);
+                res.removedInfo.uid = oldPackage.applicationInfo.uid;
+                res.removedInfo.removedPackage = oldPackage.packageName;
+                res.removedInfo.installerPackageName = ps.installerPackageName;
+                res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+                res.removedInfo.isUpdate = true;
+                res.removedInfo.origUsers = installedUsers;
+                res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
+                for (int i = 0; i < installedUsers.length; i++) {
+                    final int userId = installedUsers[i];
+                    res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
+                }
+
+                final int childCount = (oldPackage.childPackages != null)
+                        ? oldPackage.childPackages.size() : 0;
+                for (int i = 0; i < childCount; i++) {
+                    boolean childPackageUpdated = false;
+                    PackageParser.Package childPkg = oldPackage.childPackages.get(i);
+                    final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
+                    if (res.addedChildPackages != null) {
+                        PackageInstalledInfo childRes = res.addedChildPackages.get(
+                                childPkg.packageName);
+                        if (childRes != null) {
+                            childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+                            childRes.removedInfo.removedPackage = childPkg.packageName;
+                            if (childPs != null) {
+                                childRes.removedInfo.installerPackageName =
+                                        childPs.installerPackageName;
+                            }
+                            childRes.removedInfo.isUpdate = true;
+                            childRes.removedInfo.installReasons = res.removedInfo.installReasons;
+                            childPackageUpdated = true;
+                        }
+                    }
+                    if (!childPackageUpdated) {
+                        PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
+                        childRemovedRes.removedPackage = childPkg.packageName;
+                        if (childPs != null) {
+                            childRemovedRes.installerPackageName = childPs.installerPackageName;
+                        }
+                        childRemovedRes.isUpdate = false;
+                        childRemovedRes.dataRemoved = true;
+                        synchronized (mPackages) {
+                            if (childPs != null) {
+                                childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers,
+                                        true);
+                            }
+                        }
+                        if (res.removedInfo.removedChildPackages == null) {
+                            res.removedInfo.removedChildPackages = new ArrayMap<>();
+                        }
+                        res.removedInfo.removedChildPackages.put(childPkg.packageName,
+                                childRemovedRes);
+                    }
+                }
+
+                sysPkg = (isSystemApp(oldPackage));
+                if (sysPkg) {
+                    // Set the system/privileged/oem/vendor/product flags as needed
+                    final boolean privileged = isPrivilegedApp(oldPackage);
+                    final boolean oem = isOemApp(oldPackage);
+                    final boolean vendor = isVendorApp(oldPackage);
+                    final boolean product = isProductApp(oldPackage);
+                    final @ParseFlags int systemParseFlags = parseFlags;
+                    final @ScanFlags int systemScanFlags = scanFlags
+                            | SCAN_AS_SYSTEM
+                            | (privileged ? SCAN_AS_PRIVILEGED : 0)
+                            | (oem ? SCAN_AS_OEM : 0)
+                            | (vendor ? SCAN_AS_VENDOR : 0)
+                            | (product ? SCAN_AS_PRODUCT : 0);
+
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+                                + ", old=" + oldPackage);
+                    }
+                    clearCodeCache = true;
+                    res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                    pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
+                            ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+                    targetParseFlags = systemParseFlags;
+                    targetScanFlags = systemScanFlags;
+                } else { // non system replace
+                    replace = true;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replaceNonSystemPackageLI: new=" + pkg + ", old="
+                                        + oldPackage);
+                    }
+
+                    String pkgName1 = oldPackage.packageName;
+                    boolean deletedPkg = true;
+                    boolean addedPkg = false;
+                    boolean updatedSettings = false;
+
+                    final long origUpdateTime = (pkg.mExtras != null)
+                            ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
+
+                }
+            } else { // new package install
+                replace = false;
+                existingPackage = null;
+                // Remember this for later, in case we need to rollback this install
+                String pkgName1 = pkg.packageName;
+
+                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+
+                // TODO(patb): MOVE TO RECONCILE
+                synchronized (mPackages) {
+                    renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
+                    if (renamedPackage != null) {
+                        // A package with the same name is already installed, though
+                        // it has been renamed to an older name.  The package we
+                        // are trying to install should be installed as an update to
+                        // the existing one, but that has not been requested, so bail.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling package running as "
+                                        + renamedPackage);
+                    }
+                    if (mPackages.containsKey(pkgName1)) {
+                        // Don't allow installation over an existing package with the same name.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling.");
+                    }
                 }
             }
-
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSequenceNumberLP(ps, res.newUsers);
-                updateInstantAppInstallerLocked(pkgName);
+            // we're passing the freezer back to be closed in a later phase of install
+            shouldCloseFreezerBeforeReturn = false;
+            return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
+                    args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
+                    clearCodeCache, sysPkg, renamedPackage, freezer);
+        } finally {
+            if (shouldCloseFreezerBeforeReturn) {
+                freezer.close();
             }
         }
     }
@@ -17156,7 +17127,7 @@
             }
         }
 
-        removePackageLI(ps, (flags & PackageManager.DELETE_CHATTY) != 0);
+        removePackageLI(ps.name, (flags & PackageManager.DELETE_CHATTY) != 0);
 
         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
             final PackageParser.Package resolvedPkg;
@@ -22267,6 +22238,22 @@
         }
 
         @Override
+        public boolean isPlatformSigned(String packageName) {
+            PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+            if (packageSetting == null) {
+                return false;
+            }
+            PackageParser.Package pkg = packageSetting.pkg;
+            if (pkg == null) {
+                // May happen if package in on a removable sd card
+                return false;
+            }
+            return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
+                    || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+                    PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+        }
+
+        @Override
         public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
             SigningDetails sd = getSigningDetails(packageName);
             if (sd == null) {
@@ -22378,7 +22365,7 @@
         }
 
         @Override
-        public PackageParser.Package getDisabledPackage(String packageName) {
+        public PackageParser.Package getDisabledSystemPackage(String packageName) {
             synchronized (mPackages) {
                 final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
                 return (ps != null) ? ps.pkg : null;
@@ -22386,6 +22373,12 @@
         }
 
         @Override
+        public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
+            PackageParser.Package pkg = getDisabledSystemPackage(packageName);
+            return pkg == null ? null : pkg.packageName;
+        }
+
+        @Override
         public String getKnownPackageName(int knownPackage, int userId) {
             switch(knownPackage) {
                 case PackageManagerInternal.PACKAGE_BROWSER:
@@ -22423,21 +22416,6 @@
         }
 
         @Override
-        public void setSmsAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setSmsAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setDialerAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setDialerAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setSimCallManagerPackagesProvider(provider);
-        }
-
-        @Override
         public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
             mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
         }
@@ -22448,22 +22426,10 @@
         }
 
         @Override
-        public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsApp(packageName, userId);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+        public void onDefaultDialerAppChanged(String packageName, int userId) {
             synchronized (mPackages) {
                 mSettings.setDefaultDialerPackageNameLPw(packageName, userId);
             }
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerApp(packageName, userId);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManager(
-                    packageName, userId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 390c0cc..36948fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -18,23 +18,21 @@
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDWR;
+
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
 import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
 import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
-
-import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.util.FastPrintWriter;
-import com.android.server.EventLogTags;
-import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.PackageDexUsage;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppGlobals;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
@@ -53,18 +51,24 @@
 import android.system.Os;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.EventLogTags;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.PackageDexUsage;
+
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.Streams;
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileReader;
@@ -73,8 +77,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.text.SimpleDateFormat;
@@ -710,4 +712,120 @@
         final File[] compressedFiles = getCompressedFiles(codePath);
         return compressedFiles != null && compressedFiles.length > 0;
     }
+
+    /**
+     * Parse given package and return minimal details.
+     */
+    public static PackageInfoLite getMinimalPackageInfo(Context context, String packagePath,
+            int flags, String abiOverride) {
+        final PackageInfoLite ret = new PackageInfoLite();
+        if (packagePath == null) {
+            Slog.i(TAG, "Invalid package file " + packagePath);
+            ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+            return ret;
+        }
+
+        final File packageFile = new File(packagePath);
+        final PackageParser.PackageLite pkg;
+        final long sizeBytes;
+        try {
+            pkg = PackageParser.parsePackageLite(packageFile, 0);
+            sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
+        } catch (PackageParserException | IOException e) {
+            Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
+
+            if (!packageFile.exists()) {
+                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+            } else {
+                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+            }
+
+            return ret;
+        }
+
+        final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
+                pkg.packageName, pkg.installLocation, sizeBytes, flags);
+
+        ret.packageName = pkg.packageName;
+        ret.splitNames = pkg.splitNames;
+        ret.versionCode = pkg.versionCode;
+        ret.versionCodeMajor = pkg.versionCodeMajor;
+        ret.baseRevisionCode = pkg.baseRevisionCode;
+        ret.splitRevisionCodes = pkg.splitRevisionCodes;
+        ret.installLocation = pkg.installLocation;
+        ret.verifiers = pkg.verifiers;
+        ret.recommendedInstallLocation = recommendedInstallLocation;
+        ret.multiArch = pkg.multiArch;
+
+        return ret;
+    }
+
+    /**
+     * Calculate estimated footprint of given package post-installation.
+     *
+     * @return -1 if there's some error calculating the size, otherwise installed size of the
+     *         package.
+     */
+    public static long calculateInstalledSize(String packagePath, String abiOverride) {
+        final File packageFile = new File(packagePath);
+        final PackageParser.PackageLite pkg;
+        try {
+            pkg = PackageParser.parsePackageLite(packageFile, 0);
+            return PackageHelper.calculateInstalledSize(pkg, abiOverride);
+        } catch (PackageParserException | IOException e) {
+            Slog.w(TAG, "Failed to calculate installed size: " + e);
+            return -1;
+        }
+    }
+
+    /**
+     * Copy package to the target location.
+     *
+     * @param packagePath absolute path to the package to be copied. Can be
+     *                    a single monolithic APK file or a cluster directory
+     *                    containing one or more APKs.
+     * @return returns status code according to those in
+     *         {@link PackageManager}
+     */
+    public static int copyPackage(String packagePath, File targetDir) {
+        if (packagePath == null) {
+            return PackageManager.INSTALL_FAILED_INVALID_URI;
+        }
+
+        try {
+            final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
+            copyFile(pkg.baseCodePath, targetDir, "base.apk");
+            if (!ArrayUtils.isEmpty(pkg.splitNames)) {
+                for (int i = 0; i < pkg.splitNames.length; i++) {
+                    copyFile(pkg.splitCodePaths[i], targetDir,
+                            "split_" + pkg.splitNames[i] + ".apk");
+                }
+            }
+            return PackageManager.INSTALL_SUCCEEDED;
+        } catch (PackageParserException | IOException | ErrnoException e) {
+            Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
+            return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+        }
+    }
+
+    private static void copyFile(String sourcePath, File targetDir, String targetName)
+            throws ErrnoException, IOException {
+        if (!FileUtils.isValidExtFilename(targetName)) {
+            throw new IllegalArgumentException("Invalid filename: " + targetName);
+        }
+        Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
+
+        final File targetFile = new File(targetDir, targetName);
+        final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
+                O_RDWR | O_CREAT, 0644);
+        Os.chmod(targetFile.getAbsolutePath(), 0644);
+        FileInputStream source = null;
+        try {
+            source = new FileInputStream(sourcePath);
+            FileUtils.copy(source.getFD(), targetFd);
+        } finally {
+            IoUtils.closeQuietly(source);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 727fb15..b850613 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -207,4 +207,13 @@
         writeUsersInfoToProto(proto, PackageProto.USERS);
         proto.end(packageToken);
     }
+
+    /** Updates all fields in the current setting from another. */
+    public void updateFrom(PackageSetting other) {
+        super.updateFrom(other);
+        appId = other.appId;
+        pkg = other.pkg;
+        sharedUserId = other.sharedUserId;
+        sharedUser = other.sharedUser;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 138594c..fd6aceb 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -26,7 +26,6 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.Signature;
-import android.os.BaseBundle;
 import android.os.PersistableBundle;
 import android.service.pm.PackageProto;
 import android.util.ArraySet;
@@ -109,7 +108,7 @@
 
     // Whether this package is currently stopped, thus can not be
     // started until explicitly launched by the user.
-    private final SparseArray<PackageUserState> userState = new SparseArray<PackageUserState>();
+    private final SparseArray<PackageUserState> mUserState = new SparseArray<>();
 
     /**
      * Non-persisted value. During an "upgrade without restart", we need the set
@@ -118,7 +117,7 @@
      * restart, this field will be cleared since the classloader would be created
      * using the full set of code paths when the package's process is started.
      */
-    Set<String> oldCodePaths;
+    Set<String> mOldCodePaths;
 
     /** Package name of the app that installed this package */
     String installerPackageName;
@@ -223,7 +222,7 @@
     /**
      * Makes a shallow copy of the given package settings.
      *
-     * NOTE: For some fields [such as keySetData, signatures, userState, verificationInfo, etc...],
+     * NOTE: For some fields [such as keySetData, signatures, mUserState, verificationInfo, etc...],
      * the original object is copied and a new one is not created.
      */
     public void copyFrom(PackageSettingBase orig) {
@@ -244,7 +243,7 @@
         keySetData = orig.keySetData;
         lastUpdateTime = orig.lastUpdateTime;
         legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
-        // Intentionally skip oldCodePaths; it's not relevant for copies
+        // Intentionally skip mOldCodePaths; it's not relevant for copies
         parentPackageName = orig.parentPackageName;
         primaryCpuAbiString = orig.primaryCpuAbiString;
         resourcePath = orig.resourcePath;
@@ -253,9 +252,9 @@
         signatures = orig.signatures;
         timeStamp = orig.timeStamp;
         uidError = orig.uidError;
-        userState.clear();
-        for (int i=0; i<orig.userState.size(); i++) {
-            userState.put(orig.userState.keyAt(i), orig.userState.valueAt(i));
+        mUserState.clear();
+        for (int i = 0; i < orig.mUserState.size(); i++) {
+            mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i));
         }
         verificationInfo = orig.verificationInfo;
         versionCode = orig.versionCode;
@@ -271,16 +270,16 @@
     }
 
     private PackageUserState modifyUserState(int userId) {
-        PackageUserState state = userState.get(userId);
+        PackageUserState state = mUserState.get(userId);
         if (state == null) {
             state = new PackageUserState();
-            userState.put(userId, state);
+            mUserState.put(userId, state);
         }
         return state;
     }
 
     public PackageUserState readUserState(int userId) {
-        PackageUserState state = userState.get(userId);
+        PackageUserState state = mUserState.get(userId);
         if (state == null) {
             return DEFAULT_USER_STATE;
         }
@@ -330,7 +329,7 @@
     /** Only use for testing. Do NOT use in production code. */
     @VisibleForTesting
     SparseArray<PackageUserState> getUserState() {
-        return userState;
+        return mUserState;
     }
 
     boolean isAnyInstalled(int[] users) {
@@ -536,14 +535,14 @@
     }
 
     void removeUser(int userId) {
-        userState.delete(userId);
+        mUserState.delete(userId);
     }
 
     public int[] getNotInstalledUserIds() {
         int count = 0;
-        int userStateCount = userState.size();
+        int userStateCount = mUserState.size();
         for (int i = 0; i < userStateCount; i++) {
-            if (userState.valueAt(i).installed == false) {
+            if (!mUserState.valueAt(i).installed) {
                 count++;
             }
         }
@@ -551,8 +550,8 @@
         int[] excludedUserIds = new int[count];
         int idx = 0;
         for (int i = 0; i < userStateCount; i++) {
-            if (userState.valueAt(i).installed == false) {
-                excludedUserIds[idx++] = userState.keyAt(i);
+            if (!mUserState.valueAt(i).installed) {
+                excludedUserIds[idx++] = mUserState.keyAt(i);
             }
         }
         return excludedUserIds;
@@ -591,11 +590,11 @@
     }
 
     protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
-        int count = userState.size();
+        int count = mUserState.size();
         for (int i = 0; i < count; i++) {
             final long userToken = proto.start(fieldId);
-            final int userId = userState.keyAt(i);
-            final PackageUserState state = userState.valueAt(i);
+            final int userId = mUserState.keyAt(i);
+            final PackageUserState state = mUserState.valueAt(i);
             proto.write(PackageProto.UserInfoProto.ID, userId);
             final int installType;
             if (state.instantApp) {
@@ -630,4 +629,48 @@
         PackageUserState userState = readUserState(userId);
         return userState.harmfulAppWarning;
     }
+
+    protected PackageSettingBase updateFrom(PackageSettingBase other) {
+        super.copyFrom(other);
+        this.parentPackageName = other.parentPackageName;
+        this.childPackageNames = other.childPackageNames;
+        this.codePath = other.codePath;
+        this.codePathString = other.codePathString;
+        this.resourcePath = other.resourcePath;
+        this.resourcePathString = other.resourcePathString;
+        this.usesStaticLibraries = other.usesStaticLibraries;
+        this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
+        this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
+        this.primaryCpuAbiString = other.primaryCpuAbiString;
+        this.secondaryCpuAbiString = other.secondaryCpuAbiString;
+        this.cpuAbiOverrideString = other.cpuAbiOverrideString;
+        this.timeStamp = other.timeStamp;
+        this.firstInstallTime = other.firstInstallTime;
+        this.lastUpdateTime = other.lastUpdateTime;
+        this.versionCode = other.versionCode;
+        this.uidError = other.uidError;
+        this.signatures = other.signatures;
+        this.installPermissionsFixed = other.installPermissionsFixed;
+        this.keySetData = other.keySetData;
+        this.installerPackageName = other.installerPackageName;
+        this.isOrphaned = other.isOrphaned;
+        this.volumeUuid = other.volumeUuid;
+        this.categoryHint = other.categoryHint;
+        this.updateAvailable = other.updateAvailable;
+        this.verificationInfo = other.verificationInfo;
+
+        if (mOldCodePaths != null) {
+            if (other.mOldCodePaths != null) {
+                mOldCodePaths.clear();
+                mOldCodePaths.addAll(other.mOldCodePaths);
+            } else {
+                mOldCodePaths = null;
+            }
+        }
+        mUserState.clear();
+        for (int i = 0; i < other.mUserState.size(); i++) {
+            mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
+        }
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6d242f4..5c88e06 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -539,16 +539,18 @@
             if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
                 p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
-            mDisabledSysPackages.put(name, p);
-
+            final PackageSetting disabled;
             if (replaced) {
                 // a little trick...  when we install the new package, we don't
                 // want to modify the existing PackageSetting for the built-in
-                // version.  so at this point we need a new PackageSetting that
-                // is okay to muck with.
-                PackageSetting newp = new PackageSetting(p);
-                replacePackageLPw(name, newp);
+                // version.  so at this point we make a copy to place into the
+                // disabled set.
+                disabled = new PackageSetting(p);
+            } else {
+                disabled = p;
             }
+            mDisabledSysPackages.put(name, disabled);
+
             return true;
         }
         return false;
@@ -1105,19 +1107,6 @@
         mInstallerPackages.remove(packageName);
     }
 
-    private void replacePackageLPw(String name, PackageSetting newp) {
-        final PackageSetting p = mPackages.get(name);
-        if (p != null) {
-            if (p.sharedUser != null) {
-                p.sharedUser.removePackage(p);
-                p.sharedUser.addPackage(newp);
-            } else {
-                replaceUserIdLPw(p.appId, newp);
-            }
-        }
-        mPackages.put(name, newp);
-    }
-
     private boolean addUserIdLPw(int uid, Object obj, Object name) {
         if (uid > Process.LAST_APPLICATION_UID) {
             return false;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index c94d209..1a8b2af 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -24,7 +24,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -69,24 +68,26 @@
         proto.end(token);
     }
 
-    void removePackage(PackageSetting packageSetting) {
-        if (packages.remove(packageSetting)) {
-            // recalculate the pkgFlags for this shared user if needed
-            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
-                int aggregatedFlags = uidFlags;
-                for (PackageSetting ps : packages) {
-                    aggregatedFlags |= ps.pkgFlags;
-                }
-                setFlags(aggregatedFlags);
-            }
-            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
-                int aggregatedPrivateFlags = uidPrivateFlags;
-                for (PackageSetting ps : packages) {
-                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
-                }
-                setPrivateFlags(aggregatedPrivateFlags);
-            }
+    boolean removePackage(PackageSetting packageSetting) {
+        if (!packages.remove(packageSetting)) {
+            return false;
         }
+        // recalculate the pkgFlags for this shared user if needed
+        if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
+            int aggregatedFlags = uidFlags;
+            for (PackageSetting ps : packages) {
+                aggregatedFlags |= ps.pkgFlags;
+            }
+            setFlags(aggregatedFlags);
+        }
+        if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+            int aggregatedPrivateFlags = uidPrivateFlags;
+            for (PackageSetting ps : packages) {
+                aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+            }
+            setPrivateFlags(aggregatedPrivateFlags);
+        }
+        return true;
     }
 
     void addPackage(PackageSetting packageSetting) {
@@ -143,4 +144,16 @@
         }
     }
 
+    /** Updates all fields in this shared user setting from another. */
+    public SharedUserSetting updateFrom(SharedUserSetting sharedUser) {
+        copyFrom(sharedUser);
+        this.userId = sharedUser.userId;
+        this.uidFlags = sharedUser.uidFlags;
+        this.uidPrivateFlags = sharedUser.uidPrivateFlags;
+        this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
+        this.packages.clear();
+        this.packages.addAll(sharedUser.packages);
+        this.signaturesChanged = sharedUser.signaturesChanged;
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5befc1f..d9eb7e8 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -23,12 +23,13 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.DownloadManager;
+import android.app.SearchManager;
 import android.app.admin.DevicePolicyManager;
 import android.companion.CompanionDeviceManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageList;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackagesProvider;
@@ -53,6 +54,7 @@
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
 import android.security.Credentials;
+import android.speech.RecognitionService;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -61,9 +63,9 @@
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
-import com.android.server.pm.PackageManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -74,6 +76,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -95,10 +98,15 @@
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
-    private static final int DEFAULT_FLAGS =
+    @PackageManager.ResolveInfoFlags
+    private static final int DEFAULT_INTENT_QUERY_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                     | PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
+    @PackageManager.PackageInfoFlags
+    private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS =
+            PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS;
+
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
     private static final String TAG_EXCEPTIONS = "exceptions";
@@ -109,6 +117,8 @@
     private static final String ATTR_FIXED = "fixed";
 
     private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
+
+
     static {
         PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
         PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
@@ -220,7 +230,7 @@
     private final DefaultPermissionGrantedCallback mPermissionGrantedCallback;
     public interface DefaultPermissionGrantedCallback {
         /** Callback when permissions have been granted */
-        public void onDefaultRuntimePermissionsGranted(int userId);
+        void onDefaultRuntimePermissionsGranted(int userId);
     }
 
     public DefaultPermissionGrantPolicy(Context context, Looper looper,
@@ -292,9 +302,9 @@
         grantDefaultPermissionExceptions(userId);
     }
 
-    private void grantRuntimePermissionsForPackage(int userId, PackageParser.Package pkg) {
+    private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
         Set<String> permissions = new ArraySet<>();
-        for (String permission :  pkg.requestedPermissions) {
+        for (String permission : pkg.requestedPermissions) {
             final BasePermission bp = mPermissionManager.getPermission(permission);
             if (bp == null) {
                 continue;
@@ -308,36 +318,71 @@
         }
     }
 
-    private void grantAllRuntimePermissions(int userId) {
-        Log.i(TAG, "Granting all runtime permissions for user " + userId);
-        final PackageList packageList = mServiceInternal.getPackageList();
-        for (String packageName : packageList.getPackageNames()) {
-            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
-            if (pkg == null) {
-                continue;
-            }
-            grantRuntimePermissionsForPackage(userId, pkg);
-        }
-    }
-
     public void scheduleReadDefaultPermissionExceptions() {
         mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
     }
 
     private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
         Log.i(TAG, "Granting permissions to platform components for user " + userId);
-        final PackageList packageList = mServiceInternal.getPackageList();
-        for (String packageName : packageList.getPackageNames()) {
-            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
+        List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS, UserHandle.USER_SYSTEM);
+        for (PackageInfo pkg : packages) {
             if (pkg == null) {
                 continue;
             }
             if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                     || !doesPackageSupportRuntimePermissions(pkg)
-                    || pkg.requestedPermissions.isEmpty()) {
+                    || ArrayUtils.isEmpty(pkg.requestedPermissions)) {
                 continue;
             }
-            grantRuntimePermissionsForPackage(userId, pkg);
+            grantRuntimePermissionsForSystemPackage(userId, pkg);
+        }
+    }
+
+    @SafeVarargs
+    private final void grantIgnoringSystemPackage(String packageName, int userId,
+            Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, false, true, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId,
+            Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, true, false, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionsToSystemPackage(
+            String packageName, int userId, Set<String>... permissionGroups) {
+        grantPermissionsToSystemPackage(packageName, userId, false, false, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionsToSystemPackage(String packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        if (!ignoreSystemPackage && !isSystemPackage(packageName)) {
+            return;
+        }
+        grantRuntimePermissionsToPackage(getSystemPackageInfo(packageName),
+                userId, systemFixed, ignoreSystemPackage, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantRuntimePermissionsToPackage(String packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        grantRuntimePermissionsToPackage(getPackageInfo(packageName),
+                userId, systemFixed, ignoreSystemPackage, permissionGroups);
+    }
+
+    @SafeVarargs
+    private final void grantRuntimePermissionsToPackage(PackageInfo packageName, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+        if (packageName == null) return;
+        if (doesPackageSupportRuntimePermissions(packageName)) {
+            for (Set<String> permissionGroup : permissionGroups) {
+                grantRuntimePermissions(packageName, permissionGroup, systemFixed,
+                        ignoreSystemPackage, userId);
+            }
         }
     }
 
@@ -380,601 +425,373 @@
                 syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
 
         // Installer
-        final String installerPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_INSTALLER, userId);
-        PackageParser.Package installerPackage = getSystemPackage(installerPackageName);
-        if (installerPackage != null
-                && doesPackageSupportRuntimePermissions(installerPackage)) {
-            grantRuntimePermissions(installerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getKnownPackage(PackageManagerInternal.PACKAGE_INSTALLER, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Verifier
-        final String verifierPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_VERIFIER, userId);
-        PackageParser.Package verifierPackage = getSystemPackage(verifierPackageName);
-        if (verifierPackage != null
-                && doesPackageSupportRuntimePermissions(verifierPackage)) {
-            grantRuntimePermissions(verifierPackage, STORAGE_PERMISSIONS, true, userId);
-            grantRuntimePermissions(verifierPackage, PHONE_PERMISSIONS, false, userId);
-            grantRuntimePermissions(verifierPackage, SMS_PERMISSIONS, false, userId);
-        }
+        final String verifier = getKnownPackage(PackageManagerInternal.PACKAGE_VERIFIER, userId);
+        grantSystemFixedPermissionsToSystemPackage(verifier, userId, STORAGE_PERMISSIONS);
+        grantPermissionsToSystemPackage(verifier, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS);
 
         // SetupWizard
-        final String setupWizardPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId);
-        PackageParser.Package setupPackage = getSystemPackage(setupWizardPackageName);
-        if (setupPackage != null
-                && doesPackageSupportRuntimePermissions(setupPackage)) {
-            grantRuntimePermissions(setupPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, LOCATION_PERMISSIONS, userId);
-            grantRuntimePermissions(setupPackage, CAMERA_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getKnownPackage(PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId), userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, LOCATION_PERMISSIONS, CAMERA_PERMISSIONS);
 
         // Camera
-        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-        PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackage(
-                cameraIntent, userId);
-        if (cameraPackage != null
-                && doesPackageSupportRuntimePermissions(cameraPackage)) {
-            grantRuntimePermissions(cameraPackage, CAMERA_PERMISSIONS, userId);
-            grantRuntimePermissions(cameraPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(cameraPackage, STORAGE_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(MediaStore.ACTION_IMAGE_CAPTURE, userId),
+                userId, CAMERA_PERMISSIONS, MICROPHONE_PERMISSIONS, STORAGE_PERMISSIONS);
 
         // Media provider
-        PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackage(
-                MediaStore.AUTHORITY, userId);
-        if (mediaStorePackage != null) {
-            grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, MEDIA_AURAL_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, MEDIA_VISUAL_PERMISSIONS, true, userId);
-            grantRuntimePermissions(mediaStorePackage, PHONE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage(MediaStore.AUTHORITY, userId), userId,
+                STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS,
+                PHONE_PERMISSIONS);
 
         // Downloads provider
-        PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackage(
-                "downloads", userId);
-        if (downloadsPackage != null) {
-            grantRuntimePermissions(downloadsPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage("downloads", userId), userId,
+                STORAGE_PERMISSIONS);
 
         // Downloads UI
-        Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
-        PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackage(
-                downloadsUiIntent, userId);
-        if (downloadsUiPackage != null
-                && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
-            grantRuntimePermissions(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        DownloadManager.ACTION_VIEW_DOWNLOADS, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Storage provider
-        PackageParser.Package storagePackage = getDefaultProviderAuthorityPackage(
-                "com.android.externalstorage.documents", userId);
-        if (storagePackage != null) {
-            grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
-        }
-
-        // Container service
-        PackageParser.Package containerPackage = getSystemPackage(
-                PackageManagerService.DEFAULT_CONTAINER_PACKAGE);
-        if (containerPackage != null) {
-            grantRuntimePermissions(containerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultProviderAuthorityPackage("com.android.externalstorage.documents", userId),
+                userId, STORAGE_PERMISSIONS);
 
         // CertInstaller
-        Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
-        PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
-                certInstallerIntent, userId);
-        if (certInstallerPackage != null
-                && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
-            grantRuntimePermissions(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(Credentials.INSTALL_ACTION, userId), userId,
+                STORAGE_PERMISSIONS);
 
         // Dialer
         if (dialerAppPackageNames == null) {
-            Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
-            PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackage(
-                    dialerIntent, userId);
-            if (dialerPackage != null) {
-                grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
-            }
+            String dialerPackage =
+                    getDefaultSystemHandlerActivityPackage(Intent.ACTION_DIAL, userId);
+            grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
         } else {
             for (String dialerAppPackageName : dialerAppPackageNames) {
-                PackageParser.Package dialerPackage = getSystemPackage(dialerAppPackageName);
-                if (dialerPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
-                }
+                grantDefaultPermissionsToDefaultSystemDialerApp(dialerAppPackageName, userId);
             }
         }
 
         // Sim call manager
         if (simCallManagerPackageNames != null) {
             for (String simCallManagerPackageName : simCallManagerPackageNames) {
-                PackageParser.Package simCallManagerPackage =
-                        getSystemPackage(simCallManagerPackageName);
-                if (simCallManagerPackage != null) {
-                    grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage,
-                            userId);
-                }
+                grantDefaultPermissionsToDefaultSystemSimCallManager(
+                        simCallManagerPackageName, userId);
             }
         }
 
         // Use Open Wifi
         if (useOpenWifiAppPackageNames != null) {
             for (String useOpenWifiPackageName : useOpenWifiAppPackageNames) {
-                PackageParser.Package useOpenWifiPackage =
-                        getSystemPackage(useOpenWifiPackageName);
-                if (useOpenWifiPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(useOpenWifiPackage,
-                            userId);
-                }
+                grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
+                        useOpenWifiPackageName, userId);
             }
         }
 
         // SMS
         if (smsAppPackageNames == null) {
-            Intent smsIntent = new Intent(Intent.ACTION_MAIN);
-            smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
-            PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackage(
-                    smsIntent, userId);
-            if (smsPackage != null) {
-               grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
-            }
+            String smsPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_APP_MESSAGING, userId);
+            grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
         } else {
-            for (String smsPackageName : smsAppPackageNames) {
-                PackageParser.Package smsPackage = getSystemPackage(smsPackageName);
-                if (smsPackage != null) {
-                    grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
-                }
+            for (String smsPackage : smsAppPackageNames) {
+                grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
             }
         }
 
         // Cell Broadcast Receiver
-        Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
-        PackageParser.Package cbrPackage =
-                getDefaultSystemHandlerActivityPackage(cbrIntent, userId);
-        if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
-            grantRuntimePermissions(cbrPackage, SMS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
+                userId, SMS_PERMISSIONS);
 
         // Carrier Provisioning Service
-        Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION);
-        PackageParser.Package carrierProvPackage =
-                getDefaultSystemHandlerServicePackage(carrierProvIntent, userId);
-        if (carrierProvPackage != null
-                && doesPackageSupportRuntimePermissions(carrierProvPackage)) {
-            grantRuntimePermissions(carrierProvPackage, SMS_PERMISSIONS, false, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerServicePackage(Intents.SMS_CARRIER_PROVISION_ACTION, userId),
+                userId, SMS_PERMISSIONS);
 
         // Calendar
-        Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
-        calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
-        PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackage(
-                calendarIntent, userId);
-        if (calendarPackage != null
-                && doesPackageSupportRuntimePermissions(calendarPackage)) {
-            grantRuntimePermissions(calendarPackage, CALENDAR_PERMISSIONS, userId);
-            grantRuntimePermissions(calendarPackage, CONTACTS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_CALENDAR, userId),
+                userId, CALENDAR_PERMISSIONS, CONTACTS_PERMISSIONS);
 
         // Calendar provider
-        PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackage(
-                CalendarContract.AUTHORITY, userId);
-        if (calendarProviderPackage != null) {
-            grantRuntimePermissions(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(calendarProviderPackage, CALENDAR_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
-        }
+        String calendarProvider =
+                getDefaultProviderAuthorityPackage(CalendarContract.AUTHORITY, userId);
+        grantPermissionsToSystemPackage(calendarProvider, userId,
+                CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
+        grantSystemFixedPermissionsToSystemPackage(calendarProvider, userId, CALENDAR_PERMISSIONS);
 
         // Calendar provider sync adapters
-        List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackages(
-                calendarSyncAdapterPackages, userId);
-        final int calendarSyncAdapterCount = calendarSyncAdapters.size();
-        for (int i = 0; i < calendarSyncAdapterCount; i++) {
-            PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
-            if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) {
-                grantRuntimePermissions(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId);
-            }
-        }
+        grantPermissionToEachSystemPackage(
+                getHeadlessSyncAdapterPackages(calendarSyncAdapterPackages, userId),
+                userId, CALENDAR_PERMISSIONS);
 
         // Contacts
-        Intent contactsIntent = new Intent(Intent.ACTION_MAIN);
-        contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
-        PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackage(
-                contactsIntent, userId);
-        if (contactsPackage != null
-                && doesPackageSupportRuntimePermissions(contactsPackage)) {
-            grantRuntimePermissions(contactsPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(contactsPackage, PHONE_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_CONTACTS, userId),
+                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // Contacts provider sync adapters
-        List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackages(
-                contactsSyncAdapterPackages, userId);
-        final int contactsSyncAdapterCount = contactsSyncAdapters.size();
-        for (int i = 0; i < contactsSyncAdapterCount; i++) {
-            PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
-            if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) {
-                grantRuntimePermissions(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId);
-            }
-        }
+        grantPermissionToEachSystemPackage(
+                getHeadlessSyncAdapterPackages(contactsSyncAdapterPackages, userId),
+                userId, CONTACTS_PERMISSIONS);
 
         // Contacts provider
-        PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackage(
-                ContactsContract.AUTHORITY, userId);
-        if (contactsProviderPackage != null) {
-            grantRuntimePermissions(contactsProviderPackage, CONTACTS_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(contactsProviderPackage, PHONE_PERMISSIONS,
-                    true, userId);
-            grantRuntimePermissions(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
-        }
+        String contactsProviderPackage =
+                getDefaultProviderAuthorityPackage(ContactsContract.AUTHORITY, userId);
+        grantSystemFixedPermissionsToSystemPackage(contactsProviderPackage, userId,
+                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+        grantPermissionsToSystemPackage(contactsProviderPackage, userId, STORAGE_PERMISSIONS);
 
         // Device provisioning
-        Intent deviceProvisionIntent = new Intent(
-                DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
-        PackageParser.Package deviceProvisionPackage =
-                getDefaultSystemHandlerActivityPackage(deviceProvisionIntent, userId);
-        if (deviceProvisionPackage != null
-                && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
-            grantRuntimePermissions(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
+                userId, CONTACTS_PERMISSIONS);
 
         // Maps
-        Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
-        mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
-        PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackage(
-                mapsIntent, userId);
-        if (mapsPackage != null
-                && doesPackageSupportRuntimePermissions(mapsPackage)) {
-            grantRuntimePermissions(mapsPackage, LOCATION_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(Intent.CATEGORY_APP_MAPS, userId),
+                userId, LOCATION_PERMISSIONS);
 
         // Gallery
-        Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
-        galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
-        PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackage(
-                galleryIntent, userId);
-        if (galleryPackage != null
-                && doesPackageSupportRuntimePermissions(galleryPackage)) {
-            grantRuntimePermissions(galleryPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(galleryPackage, MEDIA_VISUAL_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_GALLERY, userId),
+                userId, STORAGE_PERMISSIONS, MEDIA_VISUAL_PERMISSIONS);
 
         // Email
-        Intent emailIntent = new Intent(Intent.ACTION_MAIN);
-        emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
-        PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackage(
-                emailIntent, userId);
-        if (emailPackage != null
-                && doesPackageSupportRuntimePermissions(emailPackage)) {
-            grantRuntimePermissions(emailPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(emailPackage, CALENDAR_PERMISSIONS, userId);
-        }
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackageForCategory(
+                        Intent.CATEGORY_APP_EMAIL, userId),
+                userId, CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS);
 
         // Browser
-        PackageParser.Package browserPackage = null;
-        String defaultBrowserPackage = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_BROWSER, userId);
-        if (defaultBrowserPackage != null) {
-            browserPackage = getPackage(defaultBrowserPackage);
-        }
+        String browserPackage = getKnownPackage(PackageManagerInternal.PACKAGE_BROWSER, userId);
         if (browserPackage == null) {
-            Intent browserIntent = new Intent(Intent.ACTION_MAIN);
-            browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
-            browserPackage = getDefaultSystemHandlerActivityPackage(
-                    browserIntent, userId);
+            browserPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_APP_BROWSER, userId);
+            if (!isSystemPackage(browserPackage)) {
+                browserPackage = null;
+            }
         }
-        if (browserPackage != null
-                && doesPackageSupportRuntimePermissions(browserPackage)) {
-            grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, userId);
-        }
+        grantRuntimePermissionsToPackage(browserPackage, userId,
+                false /* systemFixed */, false /* ignoreSystemPackage */,
+                LOCATION_PERMISSIONS);
 
         // Voice interaction
         if (voiceInteractPackageNames != null) {
             for (String voiceInteractPackageName : voiceInteractPackageNames) {
-                PackageParser.Package voiceInteractPackage = getSystemPackage(
-                        voiceInteractPackageName);
-                if (voiceInteractPackage != null
-                        && doesPackageSupportRuntimePermissions(voiceInteractPackage)) {
-                    grantRuntimePermissions(voiceInteractPackage,
-                            CONTACTS_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            CALENDAR_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            MICROPHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            PHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            SMS_PERMISSIONS, userId);
-                    grantRuntimePermissions(voiceInteractPackage,
-                            LOCATION_PERMISSIONS, userId);
-                }
+                grantPermissionsToSystemPackage(voiceInteractPackageName, userId,
+                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
+                        PHONE_PERMISSIONS, SMS_PERMISSIONS, LOCATION_PERMISSIONS);
             }
         }
 
         if (ActivityManager.isLowRamDeviceStatic()) {
             // Allow voice search on low-ram devices
-            Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH");
-            PackageParser.Package globalSearchPickerPackage =
-                getDefaultSystemHandlerActivityPackage(globalSearchIntent, userId);
-
-            if (globalSearchPickerPackage != null
-                    && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) {
-                grantRuntimePermissions(globalSearchPickerPackage,
-                    MICROPHONE_PERMISSIONS, false, userId);
-                grantRuntimePermissions(globalSearchPickerPackage,
-                    LOCATION_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(
+                    getDefaultSystemHandlerActivityPackage(
+                            SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
+                    userId, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
         }
 
         // Voice recognition
-        Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
-        voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackage(
-                voiceRecoIntent, userId);
-        if (voiceRecoPackage != null
-                && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
-            grantRuntimePermissions(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
-        }
+        Intent voiceRecoIntent = new Intent(RecognitionService.SERVICE_INTERFACE)
+                .addCategory(Intent.CATEGORY_DEFAULT);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerServicePackage(voiceRecoIntent, userId), userId,
+                MICROPHONE_PERMISSIONS);
 
         // Location
         if (locationPackageNames != null) {
             for (String packageName : locationPackageNames) {
-                PackageParser.Package locationPackage = getSystemPackage(packageName);
-                if (locationPackage != null
-                        && doesPackageSupportRuntimePermissions(locationPackage)) {
-                    grantRuntimePermissions(locationPackage, CONTACTS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, CALENDAR_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, MICROPHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, PHONE_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, SMS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, LOCATION_PERMISSIONS,
-                            true, userId);
-                    grantRuntimePermissions(locationPackage, CAMERA_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, SENSORS_PERMISSIONS, userId);
-                    grantRuntimePermissions(locationPackage, STORAGE_PERMISSIONS, userId);
-                }
+                grantPermissionsToSystemPackage(packageName, userId,
+                        CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
+                        PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
+                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
+                grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+                        LOCATION_PERMISSIONS);
             }
         }
 
         // Music
-        Intent musicIntent = new Intent(Intent.ACTION_VIEW);
-        musicIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")),
-                AUDIO_MIME_TYPE);
-        PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackage(
-                musicIntent, userId);
-        if (musicPackage != null
-                && doesPackageSupportRuntimePermissions(musicPackage)) {
-            grantRuntimePermissions(musicPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(musicPackage, MEDIA_AURAL_PERMISSIONS, userId);
-        }
+        Intent musicIntent = new Intent(Intent.ACTION_VIEW)
+                .addCategory(Intent.CATEGORY_DEFAULT)
+                .setDataAndType(Uri.fromFile(new File("foo.mp3")), AUDIO_MIME_TYPE);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(musicIntent, userId), userId,
+                STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
 
         // Home
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
-        homeIntent.addCategory(Intent.CATEGORY_HOME);
-        homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP);
-        PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackage(
-                homeIntent, userId);
-        if (homePackage != null
-                && doesPackageSupportRuntimePermissions(homePackage)) {
-            grantRuntimePermissions(homePackage, LOCATION_PERMISSIONS, false, userId);
-        }
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .addCategory(Intent.CATEGORY_LAUNCHER_APP);
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(homeIntent, userId), userId,
+                LOCATION_PERMISSIONS);
 
         // Watches
         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
             // Home application on watches
-            Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN);
-            wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
 
-            PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackage(
-                    wearHomeIntent, userId);
-
-            if (wearHomePackage != null
-                    && doesPackageSupportRuntimePermissions(wearHomePackage)) {
-                grantRuntimePermissions(wearHomePackage, CONTACTS_PERMISSIONS, false,
-                        userId);
-                grantRuntimePermissions(wearHomePackage, PHONE_PERMISSIONS, true, userId);
-                grantRuntimePermissions(wearHomePackage, MICROPHONE_PERMISSIONS, false,
-                        userId);
-                grantRuntimePermissions(wearHomePackage, LOCATION_PERMISSIONS, false,
-                        userId);
-            }
+            String wearPackage = getDefaultSystemHandlerActivityPackageForCategory(
+                    Intent.CATEGORY_HOME_MAIN, userId);
+            grantPermissionsToSystemPackage(wearPackage, userId,
+                    CONTACTS_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS);
+            grantSystemFixedPermissionsToSystemPackage(wearPackage, userId, PHONE_PERMISSIONS);
 
             // Fitness tracking on watches
-            Intent trackIntent = new Intent(ACTION_TRACK);
-            PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackage(
-                    trackIntent, userId);
-            if (trackPackage != null
-                    && doesPackageSupportRuntimePermissions(trackPackage)) {
-                grantRuntimePermissions(trackPackage, SENSORS_PERMISSIONS, false, userId);
-                grantRuntimePermissions(trackPackage, LOCATION_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(
+                    getDefaultSystemHandlerActivityPackage(ACTION_TRACK, userId), userId,
+                    SENSORS_PERMISSIONS, LOCATION_PERMISSIONS);
         }
 
         // Print Spooler
-        PackageParser.Package printSpoolerPackage = getSystemPackage(
-                PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
-        if (printSpoolerPackage != null
-                && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
-            grantRuntimePermissions(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(PrintManager.PRINT_SPOOLER_PACKAGE_NAME, userId,
+                LOCATION_PERMISSIONS);
 
         // EmergencyInfo
-        Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
-        PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackage(
-                emergencyInfoIntent, userId);
-        if (emergencyInfoPckg != null
-                && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
-            grantRuntimePermissions(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
-            grantRuntimePermissions(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
+                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // NFC Tag viewer
-        Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
-        nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
-        PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackage(
-                nfcTagIntent, userId);
-        if (nfcTagPkg != null
-                && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
-            grantRuntimePermissions(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
-            grantRuntimePermissions(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
-        }
+        Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
+                .setType("vnd.android.cursor.item/ndef_msg");
+        grantPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(nfcTagIntent, userId), userId,
+                CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
         // Storage Manager
-        Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
-        PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackage(
-                storageManagerIntent, userId);
-        if (storageManagerPckg != null
-                && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
-            grantRuntimePermissions(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        StorageManager.ACTION_MANAGE_STORAGE, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // Companion devices
-        PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackage(
-                CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
-        if (companionDeviceDiscoveryPackage != null
-                && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
-            grantRuntimePermissions(companionDeviceDiscoveryPackage,
-                    LOCATION_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, userId,
+                LOCATION_PERMISSIONS);
 
         // Ringtone Picker
-        Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
-        PackageParser.Package ringtonePickerPackage =
-                getDefaultSystemHandlerActivityPackage(ringtonePickerIntent, userId);
-        if (ringtonePickerPackage != null
-                && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) {
-            grantRuntimePermissions(ringtonePickerPackage,
-                    STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        RingtoneManager.ACTION_RINGTONE_PICKER, userId),
+                userId, STORAGE_PERMISSIONS);
 
         // TextClassifier Service
         String textClassifierPackageName =
                 mContext.getPackageManager().getSystemTextClassifierPackageName();
         if (!TextUtils.isEmpty(textClassifierPackageName)) {
-            PackageParser.Package textClassifierPackage =
-                    getSystemPackage(textClassifierPackageName);
-            if (textClassifierPackage != null
-                    && doesPackageSupportRuntimePermissions(textClassifierPackage)) {
-                grantRuntimePermissions(textClassifierPackage, PHONE_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, SMS_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CALENDAR_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, LOCATION_PERMISSIONS, false, userId);
-                grantRuntimePermissions(textClassifierPackage, CONTACTS_PERMISSIONS, false, userId);
-            }
+            grantPermissionsToSystemPackage(textClassifierPackageName, userId,
+                    PHONE_PERMISSIONS, SMS_PERMISSIONS, CALENDAR_PERMISSIONS,
+                    LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
         }
 
         // There is no real "marker" interface to identify the shared storage backup, it is
         // hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
-        PackageParser.Package sharedStorageBackupPackage = getSystemPackage(
-                "com.android.sharedstoragebackup");
-        if (sharedStorageBackupPackage != null) {
-            grantRuntimePermissions(sharedStorageBackupPackage, STORAGE_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
+                STORAGE_PERMISSIONS);
 
         if (mPermissionGrantedCallback != null) {
             mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId);
         }
     }
 
-    private void grantDefaultPermissionsToDefaultSystemDialerApp(
-            PackageParser.Package dialerPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(dialerPackage)) {
-            boolean isPhonePermFixed =
-                    mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
-            grantRuntimePermissions(
-                    dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
-            grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, userId);
+    private String getDefaultSystemHandlerActivityPackageForCategory(String category, int userId) {
+        return getDefaultSystemHandlerActivityPackage(
+                new Intent(Intent.ACTION_MAIN).addCategory(category), userId);
+    }
+
+    @SafeVarargs
+    private final void grantPermissionToEachSystemPackage(
+            ArrayList<String> packages, int userId, Set<String>... permissions) {
+        if (packages == null) return;
+        final int count = packages.size();
+        for (int i = 0; i < count; i++) {
+            grantPermissionsToSystemPackage(packages.get(i), userId, permissions);
         }
     }
 
-    private void grantDefaultPermissionsToDefaultSystemSmsApp(
-            PackageParser.Package smsPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(smsPackage)) {
-            grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, userId);
+    private String getKnownPackage(int knownPkgId, int userId) {
+        return mServiceInternal.getKnownPackageName(knownPkgId, userId);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemDialerApp(
+            String dialerPackage, int userId) {
+        if (dialerPackage == null) {
+            return;
         }
+        boolean isPhonePermFixed =
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
+        if (isPhonePermFixed) {
+            grantSystemFixedPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+        } else {
+            grantPermissionsToSystemPackage(dialerPackage, userId, PHONE_PERMISSIONS);
+        }
+        grantPermissionsToSystemPackage(dialerPackage, userId,
+                CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemSmsApp(String smsPackage, int userId) {
+        grantPermissionsToSystemPackage(smsPackage, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
+                STORAGE_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
-            PackageParser.Package useOpenWifiPackage, int userId) {
-        if (doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
-            grantRuntimePermissions(useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, userId);
-        }
+            String useOpenWifiPackage, int userId) {
+        grantPermissionsToSystemPackage(
+                useOpenWifiPackage, userId, COARSE_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package smsPackage = getPackage(packageName);
-        if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) {
-            grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, STORAGE_PERMISSIONS,
+                MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+        mServiceInternal.onDefaultDialerAppChanged(packageName, userId);
         Log.i(TAG, "Granting permissions to default dialer app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package dialerPackage = getPackage(packageName);
-        if (dialerPackage != null
-                && doesPackageSupportRuntimePermissions(dialerPackage)) {
-            grantRuntimePermissions(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
-            grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId,
+                PHONE_PERMISSIONS, CONTACTS_PERMISSIONS, SMS_PERMISSIONS,
+                MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package useOpenWifiPackage = getPackage(packageName);
-        if (useOpenWifiPackage != null
-                && doesPackageSupportRuntimePermissions(useOpenWifiPackage)) {
-            grantRuntimePermissions(
-                    useOpenWifiPackage, COARSE_LOCATION_PERMISSIONS, false, true, userId);
-        }
-    }
-
-    private void grantDefaultPermissionsToDefaultSimCallManager(
-            PackageParser.Package simCallManagerPackage, int userId) {
-        Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
-        if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) {
-            grantRuntimePermissions(simCallManagerPackage, PHONE_PERMISSIONS, userId);
-            grantRuntimePermissions(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId);
-        }
+        grantIgnoringSystemPackage(packageName, userId, COARSE_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
         if (packageName == null) {
             return;
         }
-        PackageParser.Package simCallManagerPackage = getPackage(packageName);
-        if (simCallManagerPackage != null) {
-            grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, userId);
+        Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
+        grantRuntimePermissionsToPackage(packageName, userId, false, false,
+                PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
+    }
+
+    private void grantDefaultPermissionsToDefaultSystemSimCallManager(
+            String packageName, int userId) {
+        if (isSystemPackage(packageName)) {
+            grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
         }
     }
 
@@ -984,13 +801,8 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package carrierPackage = getSystemPackage(packageName);
-            if (carrierPackage != null
-                    && doesPackageSupportRuntimePermissions(carrierPackage)) {
-                grantRuntimePermissions(carrierPackage, PHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(carrierPackage, LOCATION_PERMISSIONS, userId);
-                grantRuntimePermissions(carrierPackage, SMS_PERMISSIONS, userId);
-            }
+            grantPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, LOCATION_PERMISSIONS, SMS_PERMISSIONS);
         }
     }
 
@@ -1000,15 +812,9 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package imsServicePackage = getSystemPackage(packageName);
-            if (imsServicePackage != null
-                    && doesPackageSupportRuntimePermissions(imsServicePackage)) {
-                grantRuntimePermissions(imsServicePackage, PHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId);
-                grantRuntimePermissions(imsServicePackage, CONTACTS_PERMISSIONS, userId);
-            }
+            grantPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS, LOCATION_PERMISSIONS,
+                    CAMERA_PERMISSIONS, CONTACTS_PERMISSIONS);
         }
     }
 
@@ -1019,15 +825,12 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package dataServicePackage = getSystemPackage(packageName);
-            if (dataServicePackage != null
-                    && doesPackageSupportRuntimePermissions(dataServicePackage)) {
-                // Grant these permissions as system-fixed, so that nobody can accidentally
-                // break cellular data.
-                grantRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
-                grantRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
-            }
+            // Grant these permissions as system-fixed, so that nobody can accidentally
+            // break cellular data.
+            grantSystemFixedPermissionsToSystemPackage(packageName, userId,
+                    PHONE_PERMISSIONS, LOCATION_PERMISSIONS);
         }
+
     }
 
     public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
@@ -1037,25 +840,17 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package dataServicePackage = getSystemPackage(packageName);
-            if (dataServicePackage != null
-                    && doesPackageSupportRuntimePermissions(dataServicePackage)) {
-                revokeRuntimePermissions(dataServicePackage, PHONE_PERMISSIONS, true, userId);
-                revokeRuntimePermissions(dataServicePackage, LOCATION_PERMISSIONS, true, userId);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
+            if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+                revokeRuntimePermissions(packageName, PHONE_PERMISSIONS, true, userId);
+                revokeRuntimePermissions(packageName, LOCATION_PERMISSIONS, true, userId);
             }
         }
     }
 
     public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to active LUI app for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package luiAppPackage = getSystemPackage(packageName);
-        if (luiAppPackage != null
-                && doesPackageSupportRuntimePermissions(luiAppPackage)) {
-            grantRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
-        }
+        grantSystemFixedPermissionsToSystemPackage(packageName, userId, CAMERA_PERMISSIONS);
     }
 
     public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
@@ -1064,123 +859,116 @@
             return;
         }
         for (String packageName : packageNames) {
-            PackageParser.Package luiAppPackage = getSystemPackage(packageName);
-            if (luiAppPackage != null
-                    && doesPackageSupportRuntimePermissions(luiAppPackage)) {
-                revokeRuntimePermissions(luiAppPackage, CAMERA_PERMISSIONS, true, userId);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
+            if (isSystemPackage(pkg) && doesPackageSupportRuntimePermissions(pkg)) {
+                revokeRuntimePermissions(packageName, CAMERA_PERMISSIONS, true, userId);
             }
         }
     }
 
     public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default browser for user:" + userId);
-        if (packageName == null) {
-            return;
-        }
-        PackageParser.Package browserPackage = getSystemPackage(packageName);
-        if (browserPackage != null
-                && doesPackageSupportRuntimePermissions(browserPackage)) {
-            grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, false, false, userId);
-        }
+        grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
     }
 
-    private PackageParser.Package getDefaultSystemHandlerActivityPackage(
-            Intent intent, int userId) {
+    private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) {
+        return getDefaultSystemHandlerActivityPackage(new Intent(intentAction), userId);
+    }
+
+    private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) {
         ResolveInfo handler = mServiceInternal.resolveIntent(intent,
-                intent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, userId, false,
-                Binder.getCallingUid());
+                intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS,
+                userId, false, Binder.getCallingUid());
         if (handler == null || handler.activityInfo == null) {
             return null;
         }
         if (mServiceInternal.isResolveActivityComponent(handler.activityInfo)) {
             return null;
         }
-        return getSystemPackage(handler.activityInfo.packageName);
+        String packageName = handler.activityInfo.packageName;
+        return isSystemPackage(packageName) ? packageName : null;
     }
 
-    private PackageParser.Package getDefaultSystemHandlerServicePackage(
+    private String getDefaultSystemHandlerServicePackage(String intentAction, int userId) {
+        return getDefaultSystemHandlerServicePackage(new Intent(intentAction), userId);
+    }
+
+    private String getDefaultSystemHandlerServicePackage(
             Intent intent, int userId) {
         List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
-                intent, DEFAULT_FLAGS, Binder.getCallingUid(), userId);
+                intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId);
         if (handlers == null) {
             return null;
         }
         final int handlerCount = handlers.size();
         for (int i = 0; i < handlerCount; i++) {
             ResolveInfo handler = handlers.get(i);
-            PackageParser.Package handlerPackage = getSystemPackage(
-                    handler.serviceInfo.packageName);
-            if (handlerPackage != null) {
+            String handlerPackage = handler.serviceInfo.packageName;
+            if (isSystemPackage(handlerPackage)) {
                 return handlerPackage;
             }
         }
         return null;
     }
 
-    private List<PackageParser.Package> getHeadlessSyncAdapterPackages(
+    private ArrayList<String> getHeadlessSyncAdapterPackages(
             String[] syncAdapterPackageNames, int userId) {
-        List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
+        ArrayList<String> syncAdapterPackages = new ArrayList<>();
 
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
-        homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
 
         for (String syncAdapterPackageName : syncAdapterPackageNames) {
             homeIntent.setPackage(syncAdapterPackageName);
 
             ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
-                    homeIntent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS,
+                    homeIntent.resolveType(mContext.getContentResolver()),
+                    DEFAULT_INTENT_QUERY_FLAGS,
                     userId, false, Binder.getCallingUid());
             if (homeActivity != null) {
                 continue;
             }
 
-            PackageParser.Package syncAdapterPackage = getSystemPackage(syncAdapterPackageName);
-            if (syncAdapterPackage != null) {
-                syncAdapterPackages.add(syncAdapterPackage);
+            if (isSystemPackage(syncAdapterPackageName)) {
+                syncAdapterPackages.add(syncAdapterPackageName);
             }
         }
 
         return syncAdapterPackages;
     }
 
-    private PackageParser.Package getDefaultProviderAuthorityPackage(
-            String authority, int userId) {
-        ProviderInfo provider =
-                mServiceInternal.resolveContentProvider(authority, DEFAULT_FLAGS, userId);
+    private String getDefaultProviderAuthorityPackage(String authority, int userId) {
+        ProviderInfo provider = mServiceInternal.resolveContentProvider(
+                authority, DEFAULT_INTENT_QUERY_FLAGS, userId);
         if (provider != null) {
-            return getSystemPackage(provider.packageName);
+            return provider.packageName;
         }
         return null;
     }
 
-    private PackageParser.Package getPackage(String packageName) {
-        return mServiceInternal.getPackage(packageName);
+    private boolean isSystemPackage(String packageName) {
+        return isSystemPackage(getSystemPackageInfo(packageName));
     }
 
-    private PackageParser.Package getSystemPackage(String packageName) {
-        PackageParser.Package pkg = getPackage(packageName);
-        if (pkg != null && pkg.isSystem()) {
-            return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
+    private boolean isSystemPackage(PackageInfo pkg) {
+        if (pkg == null) {
+            return false;
         }
-        return null;
+        return pkg.applicationInfo.isSystemApp()
+                && !isSysComponentOrPersistentPlatformSignedPrivApp(pkg);
     }
 
-    private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
-            int userId) {
-        grantRuntimePermissions(pkg, permissions, false, false, userId);
-    }
-
-    private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+    private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions,
             boolean systemFixed, int userId) {
         grantRuntimePermissions(pkg, permissions, systemFixed, false, userId);
     }
 
-    private void revokeRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+    private void revokeRuntimePermissions(String packageName, Set<String> permissions,
             boolean systemFixed, int userId) {
-        if (pkg.requestedPermissions.isEmpty()) {
+        PackageInfo pkg = getSystemPackageInfo(packageName);
+        if (ArrayUtils.isEmpty(pkg.requestedPermissions)) {
             return;
         }
-        Set<String> revokablePermissions = new ArraySet<>(pkg.requestedPermissions);
+        Set<String> revokablePermissions = new ArraySet<>(Arrays.asList(pkg.requestedPermissions));
 
         for (String permission : permissions) {
             // We can't revoke what wasn't requested.
@@ -1189,7 +977,7 @@
             }
 
             final int flags = mServiceInternal.getPermissionFlagsTEMP(
-                    permission, pkg.packageName, userId);
+                    permission, packageName, userId);
 
             // We didn't get this through the default grant policy. Move along.
             if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) {
@@ -1205,29 +993,35 @@
             if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) {
                 continue;
             }
-            mServiceInternal.revokeRuntimePermission(pkg.packageName, permission, userId, false);
+            mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false);
 
             if (DEBUG) {
                 Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ")
-                        + permission + " to " + pkg.packageName);
+                        + permission + " to " + packageName);
             }
 
             // Remove the GRANTED_BY_DEFAULT flag without touching the others.
             // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains
             // sticky once set.
-            mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
+            mServiceInternal.updatePermissionFlagsTEMP(permission, packageName,
                     PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId);
         }
     }
 
-    private void grantRuntimePermissions(PackageParser.Package pkg,
+    private void grantRuntimePermissions(PackageInfo pkg,
             Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
             int userId) {
-        if (pkg.requestedPermissions.isEmpty()) {
+        if (pkg == null) {
+            return;
+        }
+
+        String[] requestedPermissions = pkg.requestedPermissions;
+        if (ArrayUtils.isEmpty(requestedPermissions)) {
             return;
         }
 
         final ArraySet<String> permissions = new ArraySet<>(permissionsWithoutSplits);
+        ApplicationInfo applicationInfo = pkg.applicationInfo;
 
         // Automatically attempt to grant split permissions to older APKs
         final int numSplitPerms = PackageParser.SPLIT_PERMISSIONS.length;
@@ -1235,13 +1029,13 @@
             final PackageParser.SplitPermissionInfo splitPerm =
                     PackageParser.SPLIT_PERMISSIONS[splitPermNum];
 
-            if (pkg.applicationInfo.targetSdkVersion < splitPerm.targetSdk
+            if (applicationInfo != null
+                    && applicationInfo.targetSdkVersion < splitPerm.targetSdk
                     && permissionsWithoutSplits.contains(splitPerm.rootPerm)) {
                 Collections.addAll(permissions, splitPerm.newPerms);
             }
         }
 
-        List<String> requestedPermissions = pkg.requestedPermissions;
         Set<String> grantablePermissions = null;
 
         // In some cases, like for the Phone or SMS app, we grant permissions regardless
@@ -1250,23 +1044,25 @@
         // choice to grant this app the permissions needed to function. For all other
         // apps, (default grants on first boot and user creation) we don't grant default
         // permissions if the version on the system image does not declare them.
-        if (!ignoreSystemPackage && pkg.isUpdatedSystemApp()) {
-            final PackageParser.Package disabledPkg =
-                    mServiceInternal.getDisabledPackage(pkg.packageName);
+        if (!ignoreSystemPackage
+                && applicationInfo != null
+                && applicationInfo.isUpdatedSystemApp()) {
+            final PackageInfo disabledPkg = getSystemPackageInfo(
+                    mServiceInternal.getDisabledSystemPackageName(pkg.packageName));
             if (disabledPkg != null) {
-                if (disabledPkg.requestedPermissions.isEmpty()) {
+                if (ArrayUtils.isEmpty(disabledPkg.requestedPermissions)) {
                     return;
                 }
                 if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) {
-                    grantablePermissions = new ArraySet<>(requestedPermissions);
+                    grantablePermissions = new ArraySet<>(Arrays.asList(requestedPermissions));
                     requestedPermissions = disabledPkg.requestedPermissions;
                 }
             }
         }
 
-        final int grantablePermissionCount = requestedPermissions.size();
+        final int grantablePermissionCount = requestedPermissions.length;
         for (int i = 0; i < grantablePermissionCount; i++) {
-            String permission = requestedPermissions.get(i);
+            String permission = requestedPermissions[i];
 
             // If there is a disabled system app it may request a permission the updated
             // version ot the data partition doesn't, In this case skip the permission.
@@ -1296,7 +1092,7 @@
                             pkg.packageName, permission, userId, false);
                     if (DEBUG) {
                         Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
-                                + permission + " to default handler " + pkg.packageName);
+                                + permission + " to default handler " + pkg);
                     }
 
                     int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -1315,7 +1111,7 @@
                         && !systemFixed) {
                     if (DEBUG) {
                         Log.i(TAG, "Granted not fixed " + permission + " to default handler "
-                                + pkg.packageName);
+                                + pkg);
                     }
                     mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
                             PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
@@ -1324,28 +1120,42 @@
         }
     }
 
-    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
+    private PackageInfo getSystemPackageInfo(String pkg) {
+        //TODO not MATCH_SYSTEM_ONLY?
+        return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY);
+    }
+
+    private PackageInfo getPackageInfo(String pkg) {
+        return getPackageInfo(pkg, 0 /* extraFlags */);
+    }
+
+    private PackageInfo getPackageInfo(String pkg,
+            @PackageManager.PackageInfoFlags int extraFlags) {
+        return mServiceInternal.getPackageInfo(pkg,
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags,
+                //TODO is this the right filterCallingUid?
+                UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM);
+    }
+
+    private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) {
         if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
             return true;
         }
-        if (!pkg.isPrivileged()) {
+        if (!pkg.applicationInfo.isPrivilegedApp()) {
             return false;
         }
-        final PackageParser.Package disabledPkg =
-                mServiceInternal.getDisabledPackage(pkg.packageName);
+        final PackageInfo disabledPkg = getSystemPackageInfo(
+                mServiceInternal.getDisabledSystemPackageName(pkg.applicationInfo.packageName));
         if (disabledPkg != null) {
-            if ((disabledPkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            ApplicationInfo disabledPackageAppInfo = disabledPkg.applicationInfo;
+            if (disabledPackageAppInfo != null
+                    && (disabledPackageAppInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
                 return false;
             }
         } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
             return false;
         }
-        final String systemPackageName = mServiceInternal.getKnownPackageName(
-                PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
-        final PackageParser.Package systemPackage = getPackage(systemPackageName);
-        return pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
-                || systemPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
-                        PackageParser.SigningDetails.CertCapabilities.PERMISSION);
+        return mServiceInternal.isPlatformSigned(pkg.packageName);
     }
 
     private void grantDefaultPermissionExceptions(int userId) {
@@ -1365,7 +1175,7 @@
         final int exceptionCount = mGrantExceptions.size();
         for (int i = 0; i < exceptionCount; i++) {
             String packageName = mGrantExceptions.keyAt(i);
-            PackageParser.Package pkg = getSystemPackage(packageName);
+            PackageInfo pkg = getSystemPackageInfo(packageName);
             List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
             final int permissionGrantCount = permissionGrants.size();
             for (int j = 0; j < permissionGrantCount; j++) {
@@ -1376,8 +1186,7 @@
                     permissions.clear();
                 }
                 permissions.add(permissionGrant.name);
-                grantRuntimePermissions(pkg, permissions,
-                        permissionGrant.fixed, userId);
+                grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
             }
         }
     }
@@ -1482,15 +1291,14 @@
                         outGrantExceptions.get(packageName);
                 if (packageExceptions == null) {
                     // The package must be on the system image
-                    PackageParser.Package pkg = getSystemPackage(packageName);
-                    if (pkg == null) {
+                    if (!isSystemPackage(packageName)) {
                         Log.w(TAG, "Unknown package:" + packageName);
                         XmlUtils.skipCurrentTag(parser);
                         continue;
                     }
 
                     // The package must support runtime permissions
-                    if (!doesPackageSupportRuntimePermissions(pkg)) {
+                    if (!doesPackageSupportRuntimePermissions(getSystemPackageInfo(packageName))) {
                         Log.w(TAG, "Skipping non supporting runtime permissions package:"
                                 + packageName);
                         XmlUtils.skipCurrentTag(parser);
@@ -1535,8 +1343,9 @@
         }
     }
 
-    private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
-        return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+    private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) {
+        return pkg.applicationInfo != null
+                && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
     }
 
     private static final class DefaultPermissionGrant {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index c4f90a12..4b6760c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1189,7 +1189,7 @@
                 // is granted only if it had been defined by the original application.
                 if (pkg.isUpdatedSystemApp()) {
                     final PackageParser.Package disabledPkg =
-                            mPackageManagerInt.getDisabledPackage(pkg.packageName);
+                            mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
                     final PackageSetting disabledPs =
                             (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
                     if (disabledPs != null
@@ -1221,7 +1221,7 @@
                         // packages can also get the permission.
                         if (pkg.parentPackage != null) {
                             final PackageParser.Package disabledParentPkg = mPackageManagerInt
-                                    .getDisabledPackage(pkg.parentPackage.packageName);
+                                    .getDisabledSystemPackage(pkg.parentPackage.packageName);
                             final PackageSetting disabledParentPs = (disabledParentPkg != null)
                                     ? (PackageSetting) disabledParentPkg.mExtras : null;
                             if (disabledParentPkg != null
@@ -1372,7 +1372,7 @@
             return;
         }
         final PackageParser.Package disabledPkg =
-                mPackageManagerInt.getDisabledPackage(pkg.parentPackage.packageName);
+                mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
         if (disabledPkg == null || disabledPkg.mExtras == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 05a5dd7..3b19beb 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4730,8 +4730,8 @@
         }
         final WindowManager.LayoutParams attrs = win.getAttrs();
         final boolean isDefaultDisplay = win.isDefaultDisplay();
-        final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
-                (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
+        final boolean needsToOffsetInputMethodTarget =
+                (win == mLastInputMethodTargetWindow) && (mLastInputMethodWindow != null);
         if (needsToOffsetInputMethodTarget) {
             if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
             offsetInputMethodWindowLw(mLastInputMethodWindow, displayFrames);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6f9d803..a4d42a1 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -44,6 +44,8 @@
 import android.os.IStatsCompanionService;
 import android.os.IStatsManager;
 import android.os.IStoraged;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
@@ -53,6 +55,7 @@
 import android.os.StatsLogEventWrapper;
 import android.os.SynchronousResultReceiver;
 import android.os.SystemClock;
+import android.os.Temperature;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
@@ -169,6 +172,8 @@
     private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
             new KernelUidCpuClusterTimeReader();
 
+    private static IThermalService sThermalService;
+
     public StatsCompanionService(Context context) {
         super();
         mContext = context;
@@ -213,6 +218,24 @@
         long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
         mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
         mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
+
+        // Enable push notifications of throttling from vendor thermal
+        // management subsystem via thermalservice.
+        IBinder b = ServiceManager.getService("thermalservice");
+
+        if (b != null) {
+            sThermalService = IThermalService.Stub.asInterface(b);
+            try {
+                sThermalService.registerThermalEventListener(
+                        new ThermalEventListener());
+                Slog.i(TAG, "register thermal listener successfully");
+            } catch (RemoteException e) {
+                // Should never happen.
+                Slog.e(TAG, "register thermal listener error");
+            }
+        } else {
+            Slog.e(TAG, "cannot find thermalservice, no throttling push notifications");
+        }
     }
 
     @Override
@@ -906,6 +929,7 @@
         }
 
         List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
+        binderStats.reset();
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         for (ExportedCallStat callStat : callStats) {
             StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 13 /* fields */);
@@ -934,6 +958,8 @@
         }
 
         ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
+        // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we
+        // can reset the exception stats.
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         for (Entry<String, Integer> entry : exceptionStats.entrySet()) {
             StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2 /* fields */);
@@ -950,10 +976,11 @@
         }
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+        looperStats.reset();
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         for (LooperStats.ExportedEntry entry : entries) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 9 /* fields */);
-            e.writeLong(0); // uid collection not implemented yet
+            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 10 /* fields */);
+            e.writeInt(1000); // uid collection not implemented yet
             e.writeString(entry.handlerClassName);
             e.writeString(entry.threadName);
             e.writeString(entry.messageName);
@@ -962,6 +989,7 @@
             e.writeLong(entry.recordedMessageCount);
             e.writeLong(entry.totalLatencyMicros);
             e.writeLong(entry.cpuUsageMicros);
+            e.writeBoolean(entry.isInteractive);
             pulledData.add(e);
         }
     }
@@ -1456,4 +1484,11 @@
         }
     }
 
+    // Thermal event received from vendor thermal management subsystem
+    private static final class ThermalEventListener extends IThermalEventListener.Stub {
+        @Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
+            StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
+                    isThrottling ? 1 : 0, temp.getValue());
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 14294ec..c2d8188 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -566,6 +566,7 @@
 
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.showBiometricDialog(bundle, receiver, type);
@@ -576,6 +577,7 @@
 
     @Override
     public void onBiometricAuthenticated() {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricAuthenticated();
@@ -586,6 +588,7 @@
 
     @Override
     public void onBiometricHelp(String message) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricHelp(message);
@@ -596,6 +599,7 @@
 
     @Override
     public void onBiometricError(String error) {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.onBiometricError(error);
@@ -606,6 +610,7 @@
 
     @Override
     public void hideBiometricDialog() {
+        enforceBiometricDialog();
         if (mBar != null) {
             try {
                 mBar.hideBiometricDialog();
@@ -866,6 +871,12 @@
                 "StatusBarManagerService");
     }
 
+    private void enforceBiometricDialog() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_BIOMETRIC_DIALOG,
+                "StatusBarManagerService");
+    }
+
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 6c5452a..7a3f030 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
@@ -39,12 +38,13 @@
 import android.util.IntArray;
 import android.util.Slog;
 
-import android.util.SparseBooleanArray;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.SmsApplication;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+import com.android.server.pm.permission.PermissionManagerInternal;
 
 /**
  * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -72,8 +72,8 @@
                 synchronized (mLock) {
                     if (mDefaultSmsAppRequests != null || mDefaultDialerAppRequests != null
                             || mDefaultSimCallManagerRequests != null) {
-                        final PackageManagerInternal packageManagerInternal = LocalServices
-                                .getService(PackageManagerInternal.class);
+                        final DefaultPermissionGrantPolicy permissionPolicy =
+                                getDefaultPermissionGrantPolicy();
 
                         if (mDefaultSmsAppRequests != null) {
                             ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
@@ -83,7 +83,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userid = mDefaultSmsAppRequests.get(i);
                                     mDefaultSmsAppRequests.remove(i);
-                                    packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
+                                    permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
                                             smsComponent.getPackageName(), userid);
                                 }
                             }
@@ -97,7 +97,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userId = mDefaultDialerAppRequests.get(i);
                                     mDefaultDialerAppRequests.remove(i);
-                                    packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
+                                    permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
                                             packageName, userId);
                                 }
                             }
@@ -113,7 +113,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userId = mDefaultSimCallManagerRequests.get(i);
                                     mDefaultSimCallManagerRequests.remove(i);
-                                    packageManagerInternal
+                                    permissionPolicy
                                             .grantDefaultPermissionsToDefaultSimCallManager(
                                                     packageName, userId);
                                 }
@@ -132,6 +132,11 @@
         }
     }
 
+    private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
+        return LocalServices.getService(PermissionManagerInternal.class)
+                .getDefaultPermissionGrantPolicy();
+    }
+
     private static final ComponentName SERVICE_COMPONENT = new ComponentName(
             "com.android.server.telecom",
             "com.android.server.telecom.components.TelecomService");
@@ -196,82 +201,68 @@
 
 
     private void registerDefaultAppProviders() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
+        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
 
-        // Set a callback for the package manager to query the default sms app.
-        packageManagerInternal.setSmsAppPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultSmsAppRequests == null) {
-                            mDefaultSmsAppRequests = new IntArray();
-                        }
-                        mDefaultSmsAppRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default sms app.
+        permissionPolicy.setSmsAppPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultSmsAppRequests == null) {
+                        mDefaultSmsAppRequests = new IntArray();
                     }
+                    mDefaultSmsAppRequests.add(userId);
+                    return null;
                 }
-                ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
-                        mContext, true);
-                if (smsComponent != null) {
-                    return new String[]{smsComponent.getPackageName()};
-                }
-                return null;
             }
+            ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
+                    mContext, true);
+            if (smsComponent != null) {
+                return new String[]{smsComponent.getPackageName()};
+            }
+            return null;
         });
 
-        // Set a callback for the package manager to query the default dialer app.
-        packageManagerInternal.setDialerAppPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultDialerAppRequests == null) {
-                            mDefaultDialerAppRequests = new IntArray();
-                        }
-                        mDefaultDialerAppRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default dialer app.
+        permissionPolicy.setDialerAppPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultDialerAppRequests == null) {
+                        mDefaultDialerAppRequests = new IntArray();
                     }
+                    mDefaultDialerAppRequests.add(userId);
+                    return null;
                 }
-                String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
-                if (packageName != null) {
-                    return new String[]{packageName};
-                }
-                return null;
             }
+            String packageName = DefaultDialerManager.getDefaultDialerApplication(mContext);
+            if (packageName != null) {
+                return new String[]{packageName};
+            }
+            return null;
         });
 
-        // Set a callback for the package manager to query the default sim call manager.
-        packageManagerInternal.setSimCallManagerPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-            @Override
-            public String[] getPackages(int userId) {
-                synchronized (mLock) {
-                    if (mServiceConnection == null) {
-                        if (mDefaultSimCallManagerRequests == null) {
-                            mDefaultSimCallManagerRequests = new IntArray();
-                        }
-                        mDefaultSimCallManagerRequests.add(userId);
-                        return null;
+        // Set a callback for the permission grant policy to query the default sim call manager.
+        permissionPolicy.setSimCallManagerPackagesProvider(userId -> {
+            synchronized (mLock) {
+                if (mServiceConnection == null) {
+                    if (mDefaultSimCallManagerRequests == null) {
+                        mDefaultSimCallManagerRequests = new IntArray();
                     }
+                    mDefaultSimCallManagerRequests.add(userId);
+                    return null;
                 }
-                TelecomManager telecomManager =
+            }
+            TelecomManager telecomManager =
                     (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-                PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
-                if (phoneAccount != null) {
-                    return new String[]{phoneAccount.getComponentName().getPackageName()};
-                }
-                return null;
+            PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
+            if (phoneAccount != null) {
+                return new String[]{phoneAccount.getComponentName().getPackageName()};
             }
+            return null;
         });
     }
 
     private void registerDefaultAppNotifier() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
+        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
 
         // Notify the package manager on default app changes
         final Uri defaultSmsAppUri = Settings.Secure.getUriFor(
@@ -287,17 +278,17 @@
                     ComponentName smsComponent = SmsApplication.getDefaultSmsApplication(
                             mContext, true);
                     if (smsComponent != null) {
-                        packageManagerInternal.grantDefaultPermissionsToDefaultSmsApp(
+                        permissionPolicy.grantDefaultPermissionsToDefaultSmsApp(
                                 smsComponent.getPackageName(), userId);
                     }
                 } else if (defaultDialerAppUri.equals(uri)) {
                     String packageName = DefaultDialerManager.getDefaultDialerApplication(
                             mContext);
                     if (packageName != null) {
-                        packageManagerInternal.grantDefaultPermissionsToDefaultDialerApp(
+                        permissionPolicy.grantDefaultPermissionsToDefaultDialerApp(
                                 packageName, userId);
                     }
-                    updateSimCallManagerPermissions(packageManagerInternal, userId);
+                    updateSimCallManagerPermissions(permissionPolicy, userId);
                 }
             }
         };
@@ -310,14 +301,12 @@
 
 
     private void registerCarrierConfigChangedReceiver() {
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
         BroadcastReceiver receiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                     for (int userId : UserManagerService.getInstance().getUserIds()) {
-                        updateSimCallManagerPermissions(packageManagerInternal, userId);
+                        updateSimCallManagerPermissions(getDefaultPermissionGrantPolicy(), userId);
                     }
                 }
             }
@@ -327,15 +316,15 @@
             new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null, null);
     }
 
-    private void updateSimCallManagerPermissions(PackageManagerInternal packageManagerInternal,
-            int userId) {
+    private void updateSimCallManagerPermissions(
+            DefaultPermissionGrantPolicy permissionGrantPolicy, int userId) {
         TelecomManager telecomManager =
             (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
         PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
         if (phoneAccount != null) {
             Slog.i(TAG, "updating sim call manager permissions for userId:" + userId);
             String packageName = phoneAccount.getComponentName().getPackageName();
-            packageManagerInternal.grantDefaultPermissionsToDefaultSimCallManager(
+            permissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
                 packageName, userId);
         }
     }
diff --git a/core/java/com/android/internal/textservice/LazyIntToIntMap.java b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
similarity index 91%
rename from core/java/com/android/internal/textservice/LazyIntToIntMap.java
rename to services/core/java/com/android/server/textservices/LazyIntToIntMap.java
index ca9936c..2e7f2a9 100644
--- a/core/java/com/android/internal/textservice/LazyIntToIntMap.java
+++ b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
@@ -14,21 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.internal.textservice;
+package com.android.server.textservices;
 
 import android.annotation.NonNull;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.util.function.IntUnaryOperator;
 
 /**
  * Simple int-to-int key-value-store that is to be lazily initialized with the given
  * {@link IntUnaryOperator}.
  */
-@VisibleForTesting
-public final class LazyIntToIntMap {
+final class LazyIntToIntMap {
 
     private final SparseIntArray mMap = new SparseIntArray();
 
diff --git a/services/core/java/com/android/server/textservices/LocaleUtils.java b/services/core/java/com/android/server/textservices/LocaleUtils.java
new file mode 100644
index 0000000..89d8c1e
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/LocaleUtils.java
@@ -0,0 +1,152 @@
+/*
+ * 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.server.textservices;
+
+import android.annotation.Nullable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * Provides {@code Locale} related utility methods for {@link TextServicesManagerService}.
+ * <p>This class is intentionally package-private.  Utility methods here are tightly coupled with
+ * implementation details in {@link TextServicesManagerService}.  Hence this class is not suitable
+ * for other components to directly use.</p>
+ */
+final class LocaleUtils {
+    /**
+     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
+     * checker service.
+     *
+     * <p>If the system language is English, and the region is also explicitly specified in the
+     * system locale, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * <p>If the system language is English, but no region is specified in the system locale,
+     * the following fallback order will be applied.</p>
+     * <ul>
+     * <li>("en")</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * </ul>
+     *
+     * <p>If the system language is not English, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region) (if exists)</li>
+     * <li>(system-locale-language) (if exists)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * @param systemLocale the current system locale to be taken into consideration.
+     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
+     */
+    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
+            @Nullable final Locale systemLocale) {
+        final Locale systemLocaleLanguageCountryVariant;
+        final Locale systemLocaleLanguageCountry;
+        final Locale systemLocaleLanguage;
+        if (systemLocale != null) {
+            final String language = systemLocale.getLanguage();
+            final boolean hasLanguage = !TextUtils.isEmpty(language);
+            final String country = systemLocale.getCountry();
+            final boolean hasCountry = !TextUtils.isEmpty(country);
+            final String variant = systemLocale.getVariant();
+            final boolean hasVariant = !TextUtils.isEmpty(variant);
+            if (hasLanguage && hasCountry && hasVariant) {
+                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
+            } else {
+                systemLocaleLanguageCountryVariant = null;
+            }
+            if (hasLanguage && hasCountry) {
+                systemLocaleLanguageCountry = new Locale(language, country);
+            } else {
+                systemLocaleLanguageCountry = null;
+            }
+            if (hasLanguage) {
+                systemLocaleLanguage = new Locale(language);
+            } else {
+                systemLocaleLanguage = null;
+            }
+        } else {
+            systemLocaleLanguageCountryVariant = null;
+            systemLocaleLanguageCountry = null;
+            systemLocaleLanguage = null;
+        }
+
+        final ArrayList<Locale> locales = new ArrayList<>();
+        if (systemLocaleLanguageCountryVariant != null) {
+            locales.add(systemLocaleLanguageCountryVariant);
+        }
+
+        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
+            if (systemLocaleLanguageCountry != null) {
+                // If the system language is English, and the region is also explicitly specified,
+                // following fallback order will be applied.
+                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
+                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
+                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
+                // - en
+                if (systemLocaleLanguageCountry != null) {
+                    locales.add(systemLocaleLanguageCountry);
+                }
+                if (!Locale.US.equals(systemLocaleLanguageCountry)) {
+                    locales.add(Locale.US);
+                }
+                if (!Locale.UK.equals(systemLocaleLanguageCountry)) {
+                    locales.add(Locale.UK);
+                }
+                locales.add(Locale.ENGLISH);
+            } else {
+                // If the system language is English, but no region is specified, following
+                // fallback order will be applied.
+                // - en
+                // - en_US
+                // - en_GB
+                locales.add(Locale.ENGLISH);
+                locales.add(Locale.US);
+                locales.add(Locale.UK);
+            }
+        } else {
+            // If the system language is not English, the fallback order will be
+            // - systemLocaleLanguageCountry  [if non-null]
+            // - systemLocaleLanguage  [if non-null]
+            // - en_US
+            // - en_GB
+            // - en
+            if (systemLocaleLanguageCountry != null) {
+                locales.add(systemLocaleLanguageCountry);
+            }
+            if (systemLocaleLanguage != null) {
+                locales.add(systemLocaleLanguage);
+            }
+            locales.add(Locale.US);
+            locales.add(Locale.UK);
+            locales.add(Locale.ENGLISH);
+        }
+        return locales;
+    }
+}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
similarity index 99%
rename from services/core/java/com/android/server/TextServicesManagerService.java
rename to services/core/java/com/android/server/textservices/TextServicesManagerService.java
index 708350d..23c29f8 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.textservices;
 
 import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.SubtypeLocaleUtils;
 import com.android.internal.textservice.ISpellCheckerService;
 import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
 import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesManager;
 import com.android.internal.textservice.ITextServicesSessionListener;
-import com.android.internal.textservice.LazyIntToIntMap;
 import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -475,7 +475,7 @@
                 final int subtypeCount = info.getSubtypeCount();
                 for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) {
                     final SpellCheckerSubtype subtype = info.getSubtypeAt(subtypeIndex);
-                    final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(
+                    final Locale subtypeLocale = SubtypeLocaleUtils.constructLocaleFromString(
                             subtype.getLocale());
                     if (locale.equals(subtypeLocale)) {
                         // TODO: We may have more spell checkers that fall into this category.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d3e534c..ac65826 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -409,6 +409,11 @@
 
     private InputMonitor mInputMonitor;
 
+    /**
+     * The input method window for this display.
+     */
+    WindowState mInputMethodWindow;
+
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
         final AppWindowToken atoken = w.mAppToken;
@@ -2107,18 +2112,16 @@
                 mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
             }
         }
-        final WindowState inputMethod = mService.mInputMethodWindow;
-        if (inputMethod != null && inputMethod.isVisibleLw()) {
+        if (mInputMethodWindow != null && mInputMethodWindow.isVisibleLw()) {
             // If the input method is visible and the user is typing, we don't want these touch
             // events to be intercepted and used to change focus. This would likely cause a
             // disappearance of the input method.
-            inputMethod.getTouchableRegion(mTmpRegion);
-            if (inputMethod.getDisplayId() == mDisplayId) {
+            mInputMethodWindow.getTouchableRegion(mTmpRegion);
+            if (mInputMethodWindow.getDisplayId() == mDisplayId) {
                 mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
             } else {
                 // IME is on a different display, so we need to update its tap detector.
-                // TODO(multidisplay): Remove when IME will always appear on same display.
-                inputMethod.getDisplayContent().setTouchExcludeRegion(null /* focusedTask */);
+                setTouchExcludeRegion(null /* focusedTask */);
             }
         }
         for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
@@ -2257,7 +2260,7 @@
     }
 
     void adjustForImeIfNeeded() {
-        final WindowState imeWin = mService.mInputMethodWindow;
+        final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
                 && !mDividerControllerLocked.isImeHideRequested();
         final boolean dockVisible = isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
@@ -2640,12 +2643,21 @@
     }
 
     /**
+     * Set input method window for the display.
+     * @param win Set when window added or Null when destroyed.
+     */
+    void setInputMethodWindowLocked(WindowState win) {
+        mInputMethodWindow = win;
+        computeImeTarget(true /* updateImeTarget */);
+    }
+
+    /**
      * Determine and return the window that should be the IME target.
      * @param updateImeTarget If true the system IME target will be updated to match what we found.
      * @return The window that should be used as the IME target or null if there isn't any.
      */
     WindowState computeImeTarget(boolean updateImeTarget) {
-        if (mService.mInputMethodWindow == null) {
+        if (mInputMethodWindow == null) {
             // There isn't an IME so there shouldn't be a target...That was easy!
             if (updateImeTarget) {
                 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from "
@@ -3594,6 +3606,18 @@
             final int targetPosition = findPositionForStack(position, child, false /* adding */);
             super.positionChildAt(targetPosition, child, includingParents);
 
+            if (includingParents) {
+                // We still want to move the display of this stack container to top because even the
+                // target position is adjusted to non-top, the intention of the condition is to have
+                // higher z-order to gain focus (e.g. moving a task of a fullscreen stack to front
+                // in a non-top display which is using picture-in-picture mode).
+                final int topChildPosition = getChildCount() - 1;
+                if (targetPosition < topChildPosition && position >= topChildPosition) {
+                    getParent().positionChildAt(POSITION_TOP, this /* child */,
+                            true /* includingParents */);
+                }
+            }
+
             setLayoutNeeded();
         }
 
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3309798..ef3a770 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -268,11 +268,11 @@
             }
             final InputWindowHandle dragWindowHandle =
                     mService.mDragDropController.getInputWindowHandleLocked();
-            if (dragWindowHandle != null) {
-                addInputWindowHandle(dragWindowHandle);
-            } else {
+            if (dragWindowHandle == null) {
                 Slog.w(TAG_WM, "Drag is in progress but there is no "
                         + "drag window handle.");
+            } else if (dragWindowHandle.displayId == mDisplayId) {
+                addInputWindowHandle(dragWindowHandle);
             }
         }
 
@@ -283,11 +283,11 @@
             }
             final InputWindowHandle dragWindowHandle =
                     mService.mTaskPositioningController.getDragWindowHandleLocked();
-            if (dragWindowHandle != null) {
-                addInputWindowHandle(dragWindowHandle);
-            } else {
+            if (dragWindowHandle == null) {
                 Slog.e(TAG_WM,
                         "Repositioning is in progress but there is no drag window handle.");
+            } else if (dragWindowHandle.displayId == mDisplayId) {
+                addInputWindowHandle(dragWindowHandle);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 86b14337..d92818a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -681,10 +681,11 @@
                 i--;
                 WindowState win = mService.mDestroySurface.get(i);
                 win.mDestroying = false;
-                if (mService.mInputMethodWindow == win) {
-                    mService.setInputMethodWindowLocked(null);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent.mInputMethodWindow == win) {
+                    displayContent.setInputMethodWindowLocked(null);
                 }
-                if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
+                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
                     wallpaperDestroyed = true;
                 }
                 win.destroySurfaceUnchecked();
@@ -1113,4 +1114,18 @@
             callback.accept(mChildren.get(i));
         }
     }
+
+    /**
+     * Get current topmost focused IME window in system.
+     * Will look on all displays in current Z-order.
+     */
+    WindowState getCurrentInputMethodWindow() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final DisplayContent displayContent = mChildren.get(i);
+            if (displayContent.mInputMethodWindow != null) {
+                return displayContent.mInputMethodWindow;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 8effc6b..d2696c0 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -19,17 +19,17 @@
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
 import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import android.annotation.IntDef;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -51,7 +51,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.H;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -209,7 +208,6 @@
                     // Post back to WM to handle clean-ups. We still need the input
                     // event handler for the last finishInputEvent()!
                     mService.mTaskPositioningController.finishTaskPositioning();
-                    mTask.getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
                 }
                 handled = true;
             } catch (Exception e) {
@@ -237,7 +235,7 @@
     }
 
     /**
-     * @param display The Display that the window being dragged is on.
+     * @param displayContent The Display that the window being dragged is on.
      */
     void register(DisplayContent displayContent) {
         final Display display = displayContent.getDisplay();
@@ -303,6 +301,9 @@
         }
         mDisplayContent.pauseRotationLocked();
 
+        // Notify InputMonitor to take mDragWindowHandle.
+        mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+
         mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
@@ -334,6 +335,9 @@
         mDragApplicationHandle = null;
         mDragEnded = true;
 
+        // Notify InputMonitor to remove mDragWindowHandle.
+        mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+
         // Resume rotations after a drag.
         if (DEBUG_ORIENTATION) {
             Slog.d(TAG, "Resuming rotation after re-position");
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 9cdc6b7..33416f6 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -20,14 +20,13 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.Nullable;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
-import android.os.RemoteException;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Slog;
-import android.view.Display;
 import android.view.IWindow;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputWindowHandle;
@@ -124,10 +123,8 @@
             return false;
         }
 
-        Display display = displayContent.getDisplay();
         mTaskPositioner = TaskPositioner.create(mService);
         mTaskPositioner.register(displayContent);
-        displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
 
         // We need to grab the touch focus so that the touch events during the
         // resizing/scrolling are not sent to the app. 'win' is the main window
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9381fc6..cbe7d9d 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -286,8 +286,9 @@
         boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer
                 && mFrame.bottom > windowBounds.bottom;
 
-        mTmpRect.set(mFrame.left, mFrame.top, overrideRightInset ? mTmpRect.right : mFrame.right,
-                overrideBottomInset ? mTmpRect.bottom : mFrame.bottom);
+        mTmpRect.set(mFrame.left, mFrame.top,
+                overrideRightInset ? windowBounds.right : mFrame.right,
+                overrideBottomInset ? windowBounds.bottom : mFrame.bottom);
 
         InsetUtils.insetsBetweenFrames(mTmpRect, mContentFrame, mContentInsets);
         InsetUtils.insetsBetweenFrames(mTmpRect, mVisibleFrame, mVisibleInsets);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ac496a8..793ce60 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -335,9 +335,9 @@
     public abstract void registerAppTransitionListener(AppTransitionListener listener);
 
     /**
-     * Retrieves a height of input method window.
+     * Retrieves a height of input method window for given display.
      */
-    public abstract int getInputMethodWindowVisibleHeight();
+    public abstract int getInputMethodWindowVisibleHeight(int displayId);
 
     /**
       * Saves last input method window for transition.
@@ -447,4 +447,9 @@
      * Returns {@code true} if a process that is identified by {@code client} has IME focus.
      */
     public abstract boolean inputMethodClientHasFocus(IInputMethodClient client);
+
+    /**
+     * Return the display Id for given window.
+     */
+    public abstract int getDisplayIdForWindow(IBinder windowToken);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 679e0d8..2ed09ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -650,8 +650,6 @@
     /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
 
-    WindowState mInputMethodWindow = null;
-
     boolean mHardKeyboardAvailable;
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
@@ -1414,7 +1412,7 @@
             win.mToken.addWindow(win);
             if (type == TYPE_INPUT_METHOD) {
                 win.mGivenInsetsPending = true;
-                setInputMethodWindowLocked(win);
+                displayContent.setInputMethodWindowLocked(win);
                 imMayMove = false;
             } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                 displayContent.computeImeTarget(true /* updateImeTarget */);
@@ -1687,8 +1685,9 @@
         mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
 
-        if (mInputMethodWindow == win) {
-            setInputMethodWindowLocked(null);
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent.mInputMethodWindow == win) {
+            displayContent.setInputMethodWindowLocked(null);
         }
 
         final WindowToken token = win.mToken;
@@ -1733,13 +1732,6 @@
         dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
     }
 
-    void setInputMethodWindowLocked(WindowState win) {
-        mInputMethodWindow = win;
-        final DisplayContent dc = win != null
-                ? win.getDisplayContent() : getDefaultDisplayContentLocked();
-        dc.computeImeTarget(true /* updateImeTarget */);
-    }
-
     private void updateHiddenWhileSuspendedState(ArraySet<String> packages, boolean suspended) {
         synchronized (mWindowMap) {
             mRoot.updateHiddenWhileSuspendedState(packages, suspended);
@@ -2058,8 +2050,10 @@
                 if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                     focusMayChange = isDefaultDisplay;
                 }
-                if (win.mAttrs.type == TYPE_INPUT_METHOD && mInputMethodWindow == null) {
-                    setInputMethodWindowLocked(win);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (win.mAttrs.type == TYPE_INPUT_METHOD
+                        && displayContent.mInputMethodWindow == null) {
+                    displayContent.setInputMethodWindowLocked(win);
                     imMayMove = true;
                 }
                 win.adjustStartingWindowFlags();
@@ -2222,8 +2216,9 @@
             // of a transaction to avoid artifacts.
             win.mAnimatingExit = true;
         } else {
-            if (mInputMethodWindow == win) {
-                setInputMethodWindowLocked(null);
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent.mInputMethodWindow == win) {
+                displayContent.setInputMethodWindowLocked(null);
             }
             boolean stopped = win.mAppToken != null ? win.mAppToken.mAppStopped : true;
             // We set mDestroying=true so AppWindowToken#notifyAppStopped in-to destroy surfaces
@@ -2828,7 +2823,7 @@
 
     @Override
     public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
-        return mInputMethodWindow;
+        return mRoot.getCurrentInputMethodWindow();
     }
 
     @Override
@@ -5575,10 +5570,10 @@
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
             mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
-            // TODO(multidisplay): Focused windows on default display only.
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
+            final DisplayContent displayContent = (newFocus != null) ? newFocus.getDisplayContent()
+                    : getDefaultDisplayContentLocked();
             boolean imWindowChanged = false;
-            if (mInputMethodWindow != null) {
+            if (displayContent.mInputMethodWindow != null) {
                 final WindowState prevTarget = mInputMethodTarget;
 
                 final WindowState newTarget =
@@ -5587,10 +5582,11 @@
 
                 if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
                         && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
-                    final int prevImeAnimLayer = mInputMethodWindow.mWinAnimator.mAnimLayer;
+                    final int prevImeAnimLayer =
+                            displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;
                     displayContent.assignWindowLayers(false /* setLayoutNeeded */);
-                    imWindowChanged |=
-                            prevImeAnimLayer != mInputMethodWindow.mWinAnimator.mAnimLayer;
+                    imWindowChanged |= prevImeAnimLayer
+                            != displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;
                 }
             }
 
@@ -5613,7 +5609,7 @@
 
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
 
-            if (imWindowChanged && oldFocus != mInputMethodWindow) {
+            if (imWindowChanged && oldFocus != displayContent.mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     displayContent.performLayout(true /*initial*/,  updateInputWindows);
@@ -6033,8 +6029,15 @@
         }
         synchronized (mWindowMap) {
             final Region r = new Region();
-            if (mInputMethodWindow != null) {
-                mInputMethodWindow.getTouchableRegion(r);
+            // TODO(b/111080190): this method is only return the recent focused IME touch region,
+            // For Multi-Session IME, will need to add API for given display Id to
+            // get the right IME touch region.
+            for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                final DisplayContent displayContent = mRoot.mChildren.get(i);
+                if (displayContent.mInputMethodWindow != null) {
+                    displayContent.mInputMethodWindow.getTouchableRegion(r);
+                    return r;
+                }
             }
             return r;
         }
@@ -6217,8 +6220,9 @@
         if (mFocusedApp != null) {
             mFocusedApp.writeNameToProto(proto, FOCUSED_APP);
         }
-        if (mInputMethodWindow != null) {
-            mInputMethodWindow.writeIdentifierToProto(proto, INPUT_METHOD_WINDOW);
+        final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+        if (imeWindow != null) {
+            imeWindow.writeIdentifierToProto(proto, INPUT_METHOD_WINDOW);
         }
         proto.write(DISPLAY_FROZEN, mDisplayFrozen);
         final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
@@ -6388,8 +6392,9 @@
                 pw.print("  mLastStatusBarVisibility=0x");
                         pw.println(Integer.toHexString(mLastStatusBarVisibility));
             }
-            if (mInputMethodWindow != null) {
-                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
+            final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+            if (imeWindow != null) {
+                pw.print("  mInputMethodWindow="); pw.println(imeWindow);
             }
             mWindowPlacerLocked.dump(pw, "  ");
             mRoot.mWallpaperController.dump(pw, "  ");
@@ -7287,10 +7292,9 @@
         }
 
         @Override
-        public int getInputMethodWindowVisibleHeight() {
+        public int getInputMethodWindowVisibleHeight(int displayId) {
             synchronized (mWindowMap) {
-                // TODO(multi-display): Have caller pass in the display they are interested in.
-                final DisplayContent dc = getDefaultDisplayContentLocked();
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 return dc.mDisplayFrames.getInputMethodWindowVisibleHeight();
             }
         }
@@ -7298,8 +7302,9 @@
         @Override
         public void saveLastInputMethodWindowForTransition() {
             synchronized (mWindowMap) {
-                if (mInputMethodWindow != null) {
-                    mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
+                final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+                if (imeWindow != null) {
+                    mPolicy.setLastInputMethodWindowLw(imeWindow, mInputMethodTarget);
                 }
             }
         }
@@ -7406,28 +7411,42 @@
             }
         }
 
-        @Override
-        public boolean inputMethodClientHasFocus(IInputMethodClient client) {
-            synchronized (mWindowMap) {
-                // TODO: multi-display
-                if (getDefaultDisplayContentLocked().inputMethodClientHasFocus(client)) {
-                    return true;
-                }
-
-                // Okay, how about this...  what is the current focus?
-                // It seems in some cases we may not have moved the IM
-                // target window, such as when it was in a pop-up window,
-                // so let's also look at the current focus.  (An example:
-                // go to Gmail, start searching so the keyboard goes up,
-                // press home.  Sometimes the IME won't go down.)
-                // Would be nice to fix this more correctly, but it's
-                // way at the end of a release, and this should be good enough.
-                if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
-                        && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
+    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
+        boolean hasFocus;
+        synchronized (mWindowMap) {
+            // Check all displays if any input method window has focus.
+            for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                final DisplayContent displayContent = mRoot.mChildren.get(i);
+                if (displayContent.inputMethodClientHasFocus(client)) {
                     return true;
                 }
             }
-            return false;
+
+            // Okay, how about this...  what is the current focus?
+            // It seems in some cases we may not have moved the IM
+            // target window, such as when it was in a pop-up window,
+            // so let's also look at the current focus.  (An example:
+            // go to Gmail, start searching so the keyboard goes up,
+            // press home.  Sometimes the IME won't go down.)
+            // Would be nice to fix this more correctly, but it's
+            // way at the end of a release, and this should be good enough.
+            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
+                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+        @Override
+        public int getDisplayIdForWindow(IBinder windowToken) {
+            synchronized (mWindowMap) {
+                final WindowState window = mWindowMap.get(windowToken);
+                if (window != null) {
+                    return window.getDisplayContent().getDisplayId();
+                }
+                return Display.INVALID_DISPLAY;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 637c0ea..5272b66 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -845,7 +845,7 @@
                 mWindowFrames.mContainingFrame.bottom =
                         mWindowFrames.mContainingFrame.top + frozen.height();
             }
-            final WindowState imeWin = mService.mInputMethodWindow;
+            final WindowState imeWin = mService.mRoot.getCurrentInputMethodWindow();
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
                 if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom
@@ -3734,6 +3734,8 @@
         windowInfo.focused = isFocused();
         Task task = getTask();
         windowInfo.inPictureInPicture = (task != null) && task.inPinnedWindowingMode();
+        windowInfo.hasFlagWatchOutsideTouch =
+                (mAttrs.flags & WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) != 0;
 
         if (mIsChildWindow) {
             windowInfo.parentToken = getParentWindow().mClient.asBinder();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a1132d7..4c71d65 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -114,7 +114,6 @@
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
-import android.app.backup.ISelectBackupTransportCallback;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
@@ -262,7 +261,6 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
@@ -895,7 +893,6 @@
         private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
         private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
         private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled";
-        private static final String TAG_MANDATORY_BACKUP_TRANSPORT = "mandatory_backup_transport";
         private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message";
         private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message";
         private static final String TAG_METERED_DATA_DISABLED_PACKAGES
@@ -1016,10 +1013,6 @@
         // Default title of confirm credentials screen
         String organizationName = null;
 
-        // The component name of the backup transport which has to be used if backups are mandatory
-        // or null if backups are not mandatory.
-        ComponentName mandatoryBackupTransport = null;
-
         // Message for user switcher
         String startUserSessionMessage = null;
         String endUserSessionMessage = null;
@@ -1283,11 +1276,6 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutEnabled));
                 out.endTag(null, TAG_IS_LOGOUT_ENABLED);
             }
-            if (mandatoryBackupTransport != null) {
-                out.startTag(null, TAG_MANDATORY_BACKUP_TRANSPORT);
-                out.attribute(null, ATTR_VALUE, mandatoryBackupTransport.flattenToString());
-                out.endTag(null, TAG_MANDATORY_BACKUP_TRANSPORT);
-            }
             if (startUserSessionMessage != null) {
                 out.startTag(null, TAG_START_USER_SESSION_MESSAGE);
                 out.text(startUserSessionMessage);
@@ -1476,9 +1464,6 @@
                 } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
                     isLogoutEnabled = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
-                } else if (TAG_MANDATORY_BACKUP_TRANSPORT.equals(tag)) {
-                    mandatoryBackupTransport = ComponentName.unflattenFromString(
-                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) {
                     type = parser.next();
                     if (type == XmlPullParser.TEXT) {
@@ -2603,12 +2588,32 @@
 
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
+        return getActiveAdminOrCheckPermissionForCallerLocked(who,
+                reqPolicy, /* permission= */ null);
+    }
+
+    /**
+     * Finds an active admin for the caller then checks {@code permission} if admin check failed.
+     *
+     * @return an active admin or {@code null} if there is no active admin but
+     * {@code permission} is granted
+     * @throws SecurityException if caller neither has an active admin nor {@code permission}
+     */
+    @Nullable
+    ActiveAdmin getActiveAdminOrCheckPermissionForCallerLocked(
+            ComponentName who,
+            int reqPolicy,
+            @Nullable String permission) throws SecurityException {
         ensureLocked();
         final int callingUid = mInjector.binderGetCallingUid();
 
         ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
         if (result != null) {
             return result;
+        } else if (permission != null
+                && (mContext.checkCallingPermission(permission)
+                        == PackageManager.PERMISSION_GRANTED)) {
+            return null;
         }
 
         if (who != null) {
@@ -2620,7 +2625,7 @@
 
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
                 throw new SecurityException("Admin " + admin.info.getComponent()
-                         + " does not own the device");
+                        + " does not own the device");
             }
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
                 throw new SecurityException("Admin " + admin.info.getComponent()
@@ -2636,20 +2641,39 @@
                     + admin.info.getTagForPolicy(reqPolicy));
         } else {
             throw new SecurityException("No active admin owned by uid "
-                    + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy);
+                    + callingUid + " for policy #" + reqPolicy);
         }
     }
 
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent)
             throws SecurityException {
+        return getActiveAdminOrCheckPermissionForCallerLocked(
+                who, reqPolicy, parent, /* permission= */ null);
+    }
+
+    /**
+     * Finds an active admin for the caller then checks {@code permission} if admin check failed.
+     *
+     * @return an active admin or {@code null} if there is no active admin but
+     * {@code permission} is granted
+     * @throws SecurityException if caller neither has an active admin nor {@code permission}
+     */
+    @Nullable
+    ActiveAdmin getActiveAdminOrCheckPermissionForCallerLocked(
+            ComponentName who,
+            int reqPolicy,
+            boolean parent,
+            @Nullable String permission) throws SecurityException {
         ensureLocked();
         if (parent) {
             enforceManagedProfile(mInjector.userHandleGetCallingUserId(),
                     "call APIs on the parent profile");
         }
-        ActiveAdmin admin = getActiveAdminForCallerLocked(who, reqPolicy);
+        ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                who, reqPolicy, permission);
         return parent ? admin.getParentActiveAdmin() : admin;
     }
+
     /**
      * Find the admin for the component and userId bit of the uid, then check
      * the admin's uid matches the uid.
@@ -4759,10 +4783,15 @@
                 preN = getTargetSdk(admin.info.getPackageName(),
                         userHandle) <= android.os.Build.VERSION_CODES.M;
             } else {
-                // Otherwise, make sure the caller has any active admin with the right policy.
-                admin = getActiveAdminForCallerLocked(null,
-                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
-                preN = getTargetSdk(admin.info.getPackageName(),
+                // Otherwise, make sure the caller has any active admin with the right policy or
+                // the required permission.
+                admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                        null,
+                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD,
+                        android.Manifest.permission.RESET_PASSWORD);
+                // Cannot be preN if admin is null because an exception would have been
+                // thrown before getting here
+                preN = admin == null ? false : getTargetSdk(admin.info.getPackageName(),
                         userHandle) <= android.os.Build.VERSION_CODES.M;
 
                 // As of N, password resetting to empty/null is not allowed anymore.
@@ -4778,9 +4807,9 @@
                 // As of N, password cannot be changed by the admin if it is already set.
                 if (isLockScreenSecureUnchecked(userHandle)) {
                     if (!preN) {
-                        throw new SecurityException("Admin cannot change current password");
+                        throw new SecurityException("Cannot change current password");
                     } else {
-                        Slog.e(LOG_TAG, "Admin cannot change current password");
+                        Slog.e(LOG_TAG, "Cannot change current password");
                         return false;
                     }
                 }
@@ -5151,31 +5180,37 @@
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
-            // This API can only be called by an active device admin,
-            // so try to retrieve it to check that the caller is one.
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
-
+            // Make sure the caller has any active admin with the right policy or
+            // the required permission.
+            final ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked(
+                    null,
+                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
+                    parent,
+                    android.Manifest.permission.LOCK_DEVICE);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                final ComponentName adminComponent = admin.info.getComponent();
-                // Evict key
-                if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
-                    enforceManagedProfile(
-                            callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
-                    if (!isProfileOwner(adminComponent, callingUserId)) {
-                        throw new SecurityException("Only profile owner admins can set "
-                                + "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                final ComponentName adminComponent = admin == null ?
+                        null : admin.info.getComponent();
+                if (adminComponent != null) {
+                    // For Profile Owners only, callers with only permission not allowed.
+                    if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) {
+                        // Evict key
+                        enforceManagedProfile(
+                                callingUserId, "set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                        if (!isProfileOwner(adminComponent, callingUserId)) {
+                            throw new SecurityException("Only profile owner admins can set "
+                                    + "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY");
+                        }
+                        if (parent) {
+                            throw new IllegalArgumentException(
+                                    "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
+                        }
+                        if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
+                            throw new UnsupportedOperationException(
+                                    "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
+                        }
+                        mUserManager.evictCredentialEncryptionKey(callingUserId);
                     }
-                    if (parent) {
-                        throw new IllegalArgumentException(
-                                "Cannot set FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY for the parent");
-                    }
-                    if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
-                        throw new UnsupportedOperationException(
-                                "FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY only applies to FBE devices");
-                    }
-                    mUserManager.evictCredentialEncryptionKey(callingUserId);
                 }
 
                 // Lock all users unless this is a managed profile with a separate challenge
@@ -5194,7 +5229,7 @@
                     mInjector.getTrustManager().setDeviceLockedForUser(userToLock, true);
                 }
 
-                if (SecurityLog.isLoggingEnabled()) {
+                if (SecurityLog.isLoggingEnabled() && adminComponent != null) {
                     final int affectedUserId =
                             parent ? getProfileParentId(callingUserId) : callingUserId;
                     SecurityLog.writeEvent(SecurityLog.TAG_REMOTE_LOCK,
@@ -10538,8 +10573,7 @@
         final int userId = UserHandle.getUserId(uid);
         Intent intent = null;
         if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction) ||
-                DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction) ||
-                DevicePolicyManager.POLICY_MANDATORY_BACKUPS.equals(restriction)) {
+                DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) {
             synchronized (getLockObject()) {
                 final DevicePolicyData policy = getUserData(userId);
                 final int N = policy.mAdminList.size();
@@ -10548,9 +10582,7 @@
                     if ((admin.disableCamera &&
                                 DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) ||
                         (admin.disableScreenCapture && DevicePolicyManager
-                                .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) ||
-                        (admin.mandatoryBackupTransport != null && DevicePolicyManager
-                                .POLICY_MANDATORY_BACKUPS.equals(restriction))) {
+                                .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction))) {
                         intent = createShowAdminSupportIntent(admin.info.getComponent(), userId);
                         break;
                     }
@@ -11960,12 +11992,7 @@
         }
         Preconditions.checkNotNull(admin);
         synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(
-                    admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-            if (!enabled) {
-                activeAdmin.mandatoryBackupTransport = null;
-                saveSettingsLocked(UserHandle.USER_SYSTEM);
-            }
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
 
         final long ident = mInjector.binderClearCallingIdentity();
@@ -12000,87 +12027,6 @@
     }
 
     @Override
-    public boolean setMandatoryBackupTransport(
-            ComponentName admin,
-            ComponentName backupTransportComponent) {
-        if (!mHasFeature) {
-            return false;
-        }
-        Preconditions.checkNotNull(admin);
-        enforceDeviceOwner(admin);
-
-        final int callingUid = mInjector.binderGetCallingUid();
-        final AtomicBoolean success = new AtomicBoolean(false);
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        final ISelectBackupTransportCallback selectBackupTransportCallbackInternal =
-                new ISelectBackupTransportCallback.Stub() {
-                    public void onSuccess(String transportName) {
-                        saveMandatoryBackupTransport(admin, callingUid, backupTransportComponent);
-                        success.set(true);
-                        countDownLatch.countDown();
-                    }
-
-                    public void onFailure(int reason) {
-                        countDownLatch.countDown();
-                    }
-                };
-        final long identity = mInjector.binderClearCallingIdentity();
-        try {
-            IBackupManager ibm = mInjector.getIBackupManager();
-            if (ibm != null && backupTransportComponent != null) {
-                if (!ibm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
-                    ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-                }
-                ibm.selectBackupTransportAsync(
-                        backupTransportComponent, selectBackupTransportCallbackInternal);
-                countDownLatch.await();
-                if (success.get()) {
-                    ibm.setBackupEnabled(true);
-                }
-            } else if (backupTransportComponent == null) {
-                saveMandatoryBackupTransport(admin, callingUid, backupTransportComponent);
-                success.set(true);
-            }
-        } catch (RemoteException e) {
-            throw new IllegalStateException("Failed to set mandatory backup transport.", e);
-        } catch (InterruptedException e) {
-            throw new IllegalStateException("Failed to set mandatory backup transport.", e);
-        } finally {
-            mInjector.binderRestoreCallingIdentity(identity);
-        }
-        return success.get();
-    }
-
-    private void saveMandatoryBackupTransport(
-            ComponentName admin, int callingUid, ComponentName backupTransportComponent) {
-        synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin =
-                    getActiveAdminWithPolicyForUidLocked(
-                            admin,
-                            DeviceAdminInfo.USES_POLICY_DEVICE_OWNER,
-                            callingUid);
-            if (!Objects.equals(backupTransportComponent,
-                    activeAdmin.mandatoryBackupTransport)) {
-                activeAdmin.mandatoryBackupTransport =
-                        backupTransportComponent;
-                saveSettingsLocked(UserHandle.USER_SYSTEM);
-            }
-        }
-    }
-
-    @Override
-    public ComponentName getMandatoryBackupTransport() {
-        if (!mHasFeature) {
-            return null;
-        }
-        synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin = getDeviceOwnerAdminLocked();
-            return activeAdmin == null ? null : activeAdmin.mandatoryBackupTransport;
-        }
-    }
-
-
-    @Override
     public boolean bindDeviceAdminServiceAsUser(
             @NonNull ComponentName admin, @NonNull IApplicationThread caller,
             @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c80b9d8..9d63305 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -118,6 +118,7 @@
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
 import com.android.server.textclassifier.TextClassificationManagerService;
+import com.android.server.textservices.TextServicesManagerService;
 import com.android.server.trust.TrustManagerService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.tv.TvRemoteService;
@@ -785,6 +786,8 @@
 
         boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                 "config.disable_systemtextclassifier", false);
+        boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
+                false);
         boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
                 false);
         boolean disableSlices = SystemProperties.getBoolean("config.disable_slices", false);
@@ -795,6 +798,9 @@
         boolean isWatch = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_WATCH);
 
+        boolean enableVrService = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+
         // For debugging RescueParty
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
             throw new RuntimeException();
@@ -928,7 +934,7 @@
                 traceLog.traceEnd();
             }, START_HIDL_SERVICES);
 
-            if (!isWatch) {
+            if (!isWatch && enableVrService) {
                 traceBeginAndSlog("StartVrManagerService");
                 mSystemServiceManager.startService(VrManagerService.class);
                 traceEnd();
@@ -1459,7 +1465,7 @@
                 traceEnd();
             }
 
-            if (!isWatch) {
+            if (!isWatch && !disableNetworkTime) {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
                     if (useNewTimeServices) {
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
deleted file mode 100644
index d9d4b96..0000000
--- a/services/net/java/android/net/dns/ResolvUtil.java
+++ /dev/null
@@ -1,81 +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.dns;
-
-import static android.system.OsConstants.AI_ADDRCONFIG;
-
-import android.net.Network;
-import android.net.NetworkUtils;
-import android.system.GaiException;
-import android.system.OsConstants;
-import android.system.StructAddrinfo;
-
-import libcore.io.Libcore;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-
-/**
- * DNS resolution utility class.
- *
- * @hide
- */
-public class ResolvUtil {
-    // Non-portable DNS resolution flag.
-    private static final long NETID_USE_LOCAL_NAMESERVERS = 0x80000000L;
-
-    private ResolvUtil() {}
-
-    public static InetAddress[] blockingResolveAllLocally(Network network, String name)
-            throws UnknownHostException {
-        // Use AI_ADDRCONFIG by default
-        return blockingResolveAllLocally(network, name, AI_ADDRCONFIG);
-    }
-
-    public static InetAddress[] blockingResolveAllLocally(
-            Network network, String name, int aiFlags) throws UnknownHostException  {
-        final StructAddrinfo hints = new StructAddrinfo();
-        hints.ai_flags = aiFlags;
-        // Other hints identical to the default Inet6AddressImpl implementation
-        hints.ai_family = OsConstants.AF_UNSPEC;
-        hints.ai_socktype = OsConstants.SOCK_STREAM;
-
-        final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
-
-        try {
-            return Libcore.os.android_getaddrinfo(name, hints, (int) networkForResolv.netId);
-        } catch (GaiException gai) {
-            gai.rethrowAsUnknownHostException(name + ": TLS-bypass resolution failed");
-            return null;  // keep compiler quiet
-        }
-    }
-
-    public static Network getNetworkWithUseLocalNameserversFlag(Network network) {
-        final long netidForResolv = NETID_USE_LOCAL_NAMESERVERS | (long) network.netId;
-        return new Network((int) netidForResolv);
-    }
-
-    public static Network makeNetworkWithPrivateDnsBypass(Network network) {
-        return new Network(network) {
-            @Override
-            public InetAddress[] getAllByName(String host) throws UnknownHostException {
-                return blockingResolveAllLocally(network, host);
-            }
-        };
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/net/java/android/net/ip/IpServer.java
similarity index 89%
rename from services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
rename to services/net/java/android/net/ip/IpServer.java
index 5accb45..823c0a1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static android.net.NetworkUtils.numericToInetAddress;
 import static android.net.util.NetworkConstants.asByte;
@@ -31,11 +31,10 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.InterfaceController;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
+import android.net.util.NetdService;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -67,7 +66,22 @@
  *
  * @hide
  */
-public class TetherInterfaceStateMachine extends StateMachine {
+public class IpServer extends StateMachine {
+    public static final int STATE_UNAVAILABLE = 0;
+    public static final int STATE_AVAILABLE   = 1;
+    public static final int STATE_TETHERED    = 2;
+    public static final int STATE_LOCAL_ONLY  = 3;
+
+    public static String getStateString(int state) {
+        switch (state) {
+            case STATE_UNAVAILABLE: return "UNAVAILABLE";
+            case STATE_AVAILABLE:   return "AVAILABLE";
+            case STATE_TETHERED:    return "TETHERED";
+            case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
+        }
+        return "UNKNOWN: " + state;
+    }
+
     private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
     private static final byte DOUG_ADAMS = (byte) 42;
 
@@ -83,15 +97,53 @@
     // TODO: have this configurable
     private static final int DHCP_LEASE_TIME_SECS = 3600;
 
-    private final static String TAG = "TetherInterfaceSM";
+    private final static String TAG = "IpServer";
     private final static boolean DBG = false;
     private final static boolean VDBG = false;
     private static final Class[] messageClasses = {
-            TetherInterfaceStateMachine.class
+            IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
 
+    public static class Callback {
+        /**
+         * Notify that |who| has changed its tethering state.
+         *
+         * @param who the calling instance of IpServer
+         * @param state one of STATE_*
+         * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+         */
+        public void updateInterfaceState(IpServer who, int state, int lastError) {}
+
+        /**
+         * Notify that |who| has new LinkProperties.
+         *
+         * @param who the calling instance of IpServer
+         * @param newLp the new LinkProperties to report
+         */
+        public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
+    }
+
+    public static class Dependencies {
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
+            return new RouterAdvertisementDaemon(ifParams);
+        }
+
+        public InterfaceParams getInterfaceParams(String ifName) {
+            return InterfaceParams.getByName(ifName);
+        }
+
+        public INetd getNetdService() {
+            return NetdService.getInstance();
+        }
+
+        public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+                DhcpServingParams params, SharedLog log) {
+            return new DhcpServer(looper, iface, params, log);
+        }
+    }
+
     private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
     // request from the user that it wants to tether
     public static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
@@ -123,7 +175,7 @@
     private final INetworkManagementService mNMService;
     private final INetd mNetd;
     private final INetworkStatsService mStatsService;
-    private final IControlsTethering mTetherController;
+    private final Callback mCallback;
     private final InterfaceController mInterfaceCtrl;
 
     private final String mIfaceName;
@@ -131,7 +183,7 @@
     private final LinkProperties mLinkProperties;
     private final boolean mUsingLegacyDhcp;
 
-    private final TetheringDependencies mDeps;
+    private final Dependencies mDeps;
 
     private int mLastError;
     private int mServingMode;
@@ -148,17 +200,16 @@
     private DhcpServer mDhcpServer;
     private RaParams mLastRaParams;
 
-    public TetherInterfaceStateMachine(
+    public IpServer(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
             INetworkManagementService nMService, INetworkStatsService statsService,
-            IControlsTethering tetherController, boolean usingLegacyDhcp,
-            TetheringDependencies deps) {
+            Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
         super(ifaceName, looper);
         mLog = log.forSubComponent(ifaceName);
         mNMService = nMService;
         mNetd = deps.getNetdService();
         mStatsService = statsService;
-        mTetherController = tetherController;
+        mCallback = callback;
         mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
@@ -167,7 +218,7 @@
         mDeps = deps;
         resetLinkProperties();
         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-        mServingMode = IControlsTethering.STATE_AVAILABLE;
+        mServingMode = STATE_AVAILABLE;
 
         mInitialState = new InitialState();
         mLocalHotspotState = new LocalHotspotState();
@@ -379,6 +430,8 @@
             params.mtu = v6only.getMtu();
             params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
 
+            if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
+
             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
 
@@ -498,6 +551,20 @@
         }
     }
 
+    private byte getHopLimit(String upstreamIface) {
+        try {
+            int upstreamHopLimit = Integer.parseUnsignedInt(
+                    mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
+            // Add one hop to account for this forwarding device
+            upstreamHopLimit++;
+            // Cap the hop limit to 255.
+            return (byte) Integer.min(upstreamHopLimit, 255);
+        } catch (Exception e) {
+            mLog.e("Failed to find upstream interface hop limit", e);
+        }
+        return RaParams.DEFAULT_HOPLIMIT;
+    }
+
     private void setRaParams(RaParams newParams) {
         if (mRaDaemon != null) {
             final RaParams deprecatedParams =
@@ -521,14 +588,12 @@
 
     private void sendInterfaceState(int newInterfaceState) {
         mServingMode = newInterfaceState;
-        mTetherController.updateInterfaceState(
-                TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
+        mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
         sendLinkProperties();
     }
 
     private void sendLinkProperties() {
-        mTetherController.updateLinkProperties(
-                TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
+        mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
     }
 
     private void resetLinkProperties() {
@@ -539,7 +604,7 @@
     class InitialState extends State {
         @Override
         public void enter() {
-            sendInterfaceState(IControlsTethering.STATE_AVAILABLE);
+            sendInterfaceState(STATE_AVAILABLE);
         }
 
         @Override
@@ -549,10 +614,10 @@
                 case CMD_TETHER_REQUESTED:
                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                     switch (message.arg1) {
-                        case IControlsTethering.STATE_LOCAL_ONLY:
+                        case STATE_LOCAL_ONLY:
                             transitionTo(mLocalHotspotState);
                             break;
-                        case IControlsTethering.STATE_TETHERED:
+                        case STATE_TETHERED:
                             transitionTo(mTetheredState);
                             break;
                         default:
@@ -649,7 +714,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class LocalHotspotState extends BaseServingState {
         @Override
         public void enter() {
@@ -659,7 +724,7 @@
             }
 
             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
+            sendInterfaceState(STATE_LOCAL_ONLY);
         }
 
         @Override
@@ -685,7 +750,7 @@
     // problematic because transitioning during a multi-state jump yields
     // a Log.wtf(). Ultimately, there should be only one ServingState,
     // and forwarding and NAT rules should be handled by a coordinating
-    // functional element outside of TetherInterfaceStateMachine.
+    // functional element outside of IpServer.
     class TetheredState extends BaseServingState {
         @Override
         public void enter() {
@@ -695,7 +760,7 @@
             }
 
             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_TETHERED);
+            sendInterfaceState(STATE_TETHERED);
         }
 
         @Override
@@ -817,7 +882,7 @@
         @Override
         public void enter() {
             mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
-            sendInterfaceState(IControlsTethering.STATE_UNAVAILABLE);
+            sendInterfaceState(STATE_UNAVAILABLE);
         }
     }
 
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index 91a8857..57ebbfc 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -52,7 +52,6 @@
 import com.android.server.testing.FrameworkRobolectricTestRunner;
 import com.android.server.testing.SystemLoaderPackages;
 import com.android.server.testing.shadows.ShadowAppBackupUtils;
-import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer;
 import com.android.server.testing.shadows.ShadowBinder;
 import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
 import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
@@ -73,10 +72,7 @@
 import org.robolectric.shadows.ShadowSettings;
 
 @RunWith(FrameworkRobolectricTestRunner.class)
-@Config(
-        manifest = Config.NONE,
-        sdk = 26,
-        shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class})
+@Config(manifest = Config.NONE, sdk = 26, shadows = {ShadowAppBackupUtils.class})
 @SystemLoaderPackages({"com.android.server.backup"})
 @Presubmit
 public class BackupManagerServiceTest {
@@ -118,15 +114,12 @@
         mBaseStateDir = new File(cacheDir, "base_state");
         // Corresponds to /cache/backup_stage
         mDataDir = new File(cacheDir, "data");
-
-        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
     }
 
     @After
     public void tearDown() throws Exception {
         mBackupThread.quit();
         ShadowAppBackupUtils.reset();
-        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
     }
 
     /* Tests for destination string */
@@ -252,7 +245,6 @@
     private ComponentName mNewTransportComponent;
     private TransportData mNewTransport;
     private TransportMock mNewTransportMock;
-    private ComponentName mOldTransportComponent;
     private TransportData mOldTransport;
     private TransportMock mOldTransportMock;
 
@@ -260,7 +252,6 @@
         mNewTransport = backupTransport();
         mNewTransportComponent = mNewTransport.getTransportComponent();
         mOldTransport = d2dTransport();
-        mOldTransportComponent = mOldTransport.getTransportComponent();
         List<TransportMock> transportMocks =
                 setUpTransports(mTransportManager, mNewTransport, mOldTransport, localTransport());
         mNewTransportMock = transportMocks.get(0);
@@ -314,42 +305,6 @@
     }
 
     @Test
-    public void testSelectBackupTransportAsync_whenMandatoryTransport() throws Exception {
-        setUpForSelectTransport();
-        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mNewTransportComponent);
-        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
-                .thenReturn(BackupManager.SUCCESS);
-        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-        BackupManagerService backupManagerService = createInitializedBackupManagerService();
-
-        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
-
-        mShadowBackupLooper.runToEndOfTasks();
-        assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
-        verify(callback).onSuccess(eq(mNewTransport.transportName));
-        verify(mTransportManager)
-                .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any());
-    }
-
-    @Test
-    public void testSelectBackupTransportAsync_whenOtherThanMandatoryTransport() throws Exception {
-        setUpForSelectTransport();
-        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(mOldTransportComponent);
-        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
-                .thenReturn(BackupManager.SUCCESS);
-        ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
-        BackupManagerService backupManagerService = createInitializedBackupManagerService();
-
-        backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
-
-        mShadowBackupLooper.runToEndOfTasks();
-        assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
-        verify(callback).onFailure(eq(BackupManager.ERROR_BACKUP_NOT_ALLOWED));
-    }
-
-    @Test
     public void testSelectBackupTransportAsync_whenRegistrationFails() throws Exception {
         setUpForSelectTransport();
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupPolicyEnforcer.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupPolicyEnforcer.java
deleted file mode 100644
index e76b9d1..0000000
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupPolicyEnforcer.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.android.server.testing.shadows;
-
-import android.annotation.Nullable;
-import android.content.ComponentName;
-
-import com.android.server.backup.BackupPolicyEnforcer;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(BackupPolicyEnforcer.class)
-public class ShadowBackupPolicyEnforcer {
-    @Nullable private static ComponentName sMandatoryBackupTransport;
-
-    public static void setMandatoryBackupTransport(
-            @Nullable ComponentName backupTransportComponent) {
-        sMandatoryBackupTransport = backupTransportComponent;
-    }
-
-    @Implementation
-    @Nullable
-    public ComponentName getMandatoryBackupTransport() {
-        return sMandatoryBackupTransport;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
index 1c025cf..aad7230 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityGestureDetectorTest.java
@@ -18,23 +18,22 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityService;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.os.Looper;
 import android.util.DisplayMetrics;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
-import java.util.ArrayList;
+
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.util.ArrayList;
 
 /**
  * Tests for AccessibilityGestureDetector
@@ -50,14 +49,6 @@
     private AccessibilityGestureDetector mDetector;
     private AccessibilityGestureDetector.Listener mResultListener;
 
-
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         // Construct a mock Context.
@@ -67,7 +58,6 @@
         Resources mockResources = mock(Resources.class);
         when(mockResources.getDisplayMetrics()).thenReturn(displayMetricsMock);
         Context contextMock = mock(Context.class);
-        when(contextMock.getMainLooper()).thenReturn(Looper.myLooper());
         when(contextMock.getResources()).thenReturn(mockResources);
 
         // Construct a testable AccessibilityGestureDetector.
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
index 4c0f38a..b9b6d55 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerTest.java
@@ -29,7 +29,6 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Instrumentation;
-import android.os.Looper;
 import android.os.UserHandle;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -41,8 +40,8 @@
 
 import com.android.internal.util.IntPair;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -63,13 +62,6 @@
     private MessageCapturingHandler mHandler;
     private Instrumentation mInstrumentation;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -77,6 +69,12 @@
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     private AccessibilityManager createManager(boolean enabled) throws Exception {
         long serviceReturnValue = IntPair.of(
                 (enabled) ? AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED : 0,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 412e844..66d9345 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -33,16 +33,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -74,13 +72,6 @@
 
     MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -98,6 +89,12 @@
                 mMockGlobalActionPerformer);
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     @Test
     public void bind_requestsContextToBindService() {
         mConnection.bindLocked();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
index a3decb9..44a514f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureControllerTest.java
@@ -16,19 +16,8 @@
 
 package com.android.server.accessibility;
 
-import android.accessibilityservice.FingerprintGestureController;
-import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
-import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.os.Looper;
-import android.support.test.filters.FlakyTest;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static android.accessibilityservice.FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN;
+import static android.accessibilityservice.FingerprintGestureController
+        .FINGERPRINT_GESTURE_SWIPE_DOWN;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -38,6 +27,15 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.FingerprintGestureController;
+import android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 /**
  * Tests for FingerprintGestureController.
  * TODO: These tests aren't really for server code, so this isn't their ideal home.
@@ -47,13 +45,6 @@
     @Mock FingerprintGestureCallback mMockFingerprintGestureCallback;
     FingerprintGestureController mFingerprintGestureController;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -97,7 +88,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testDetectionActiveCallback_withHandler_shouldPostRunnableToHandler() {
         MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
             message.getCallback().run();
@@ -127,6 +117,8 @@
         mFingerprintGestureController.onGestureDetectionActiveChanged(false);
         assertFalse(messageCapturingHandler.hasMessages());
         verifyZeroInteractions(mMockFingerprintGestureCallback);
+
+        messageCapturingHandler.removeAllMessages();
     }
 
     @Test
@@ -145,7 +137,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testGestureCallback_withHandler_shouldPostRunnableToHandler() {
         MessageCapturingHandler messageCapturingHandler = new MessageCapturingHandler((message) -> {
             message.getCallback().run();
@@ -167,5 +158,7 @@
         mFingerprintGestureController.onGesture(FINGERPRINT_GESTURE_SWIPE_DOWN);
         assertFalse(messageCapturingHandler.hasMessages());
         verifyZeroInteractions(mMockFingerprintGestureCallback);
+
+        messageCapturingHandler.removeAllMessages();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
index 6ce7bbe..de7bc44 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/FingerprintGestureDispatcherTest.java
@@ -16,25 +16,6 @@
 
 package com.android.server.accessibility;
 
-import android.accessibilityservice.FingerprintGestureController;
-import android.content.res.Resources;
-import android.hardware.fingerprint.IFingerprintService;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.view.KeyEvent;
-
-import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-import java.util.Collections;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyBoolean;
@@ -44,6 +25,22 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.FingerprintGestureController;
+import android.content.res.Resources;
+import android.hardware.fingerprint.IFingerprintService;
+import android.view.KeyEvent;
+
+import com.android.server.accessibility.FingerprintGestureDispatcher.FingerprintGestureClient;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
 /**
  * Tests for FingerprintGestureDispatcher
  */
@@ -57,13 +54,6 @@
     private MessageCapturingHandler mMessageCapturingHandler;
     private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -77,6 +67,12 @@
         when(mGestureCapturingClient.isCapturingFingerprintGestures()).thenReturn(true);
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testNoServices_doesNotCrashOrConsumeGestures() {
         mFingerprintGestureDispatcher.onClientActiveChanged(true);
@@ -171,7 +167,7 @@
     }
 
     @Test
-    public void ifGestureDectionNotSupported_neverSaysAvailable() throws Exception {
+    public void ifGestureDetectionNotSupported_neverSaysAvailable() throws Exception {
         when(mMockResources.getBoolean(anyInt())).thenReturn(false);
         // Need to create a new dispatcher, since it picks up the resource value in its
         // constructor. This is fine since hardware config values don't change dynamically.
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index 236b458..23ce483 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -40,6 +40,7 @@
 import android.os.RemoteException;
 import android.view.KeyEvent;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.KeyEventDispatcher.KeyEventFilter;
@@ -47,16 +48,14 @@
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 
 /**
  * Tests for KeyEventDispatcher
@@ -68,7 +67,7 @@
     private final KeyEvent mKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x40);
     private final KeyEvent mOtherKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, 0x50);
     private final Object mLock = new Object();
-    private MessageCapturingHandler mInputEventsHander;
+    private MessageCapturingHandler mInputEventsHandler;
     private KeyEventDispatcher mKeyEventDispatcher;
     private KeyEventFilter mKeyEventFilter1;
     private KeyEventFilter mKeyEventFilter2;
@@ -77,23 +76,17 @@
     private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
     private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
-        mInputEventsHander = new MessageCapturingHandler();
+        Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        mInputEventsHandler = new MessageCapturingHandler(looper, null);
         mMockPowerManagerService = mock(IPowerManager.class);
         // TODO: It would be better to mock PowerManager rather than its binder, but the class is
         // final.
         PowerManager powerManager =
-                new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler());
-        mMessageCapturingHandler = new MessageCapturingHandler();
-        mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHander, SEND_FRAMEWORK_KEY_EVENT,
+                new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler(looper));
+        mMessageCapturingHandler = new MessageCapturingHandler(looper, null);
+        mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, SEND_FRAMEWORK_KEY_EVENT,
                 mLock, powerManager, mMessageCapturingHandler);
 
         mKeyEventFilter1 = mock(KeyEventFilter.class);
@@ -107,10 +100,17 @@
                 .thenReturn(true);
     }
 
+    @After
+    public void tearDown() {
+        mInputEventsHandler.removeAllMessages();
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testNotifyKeyEvent_withNoBoundServices_shouldReturnFalse() {
         assertFalse(mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Collections.EMPTY_LIST));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -119,7 +119,7 @@
         when(keyEventFilter.onKeyEvent((KeyEvent) anyObject(), anyInt())).thenReturn(false);
         assertFalse(mKeyEventDispatcher
                 .notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(keyEventFilter)));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -152,9 +152,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -166,10 +166,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -182,9 +182,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -198,10 +198,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -215,10 +215,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     @Test
@@ -232,10 +232,10 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
     // Each event should have its result set only once, but if it's set twice, we should ignore
@@ -249,14 +249,14 @@
                 mFilter1SequenceCaptor.getValue());
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         // Verify event is sent properly when other service responds
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
-        assertFalse(mMessageCapturingHandler.isTimeoutPending());
+        assertFalse(isTimeoutPending(mMessageCapturingHandler));
     }
 
 
@@ -269,9 +269,9 @@
                 mKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -284,9 +284,9 @@
                 mFilter1SequenceCaptor.getValue());
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -300,9 +300,9 @@
                 mFilter1SequenceCaptor.getValue());
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
     }
@@ -310,34 +310,34 @@
     @Test
     public void testEventTimesOut_thenServiceReturnsFalse_shouldPassToFrameworkOnce() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
     @Test
     public void testEventTimesOut_afterServiceReturnsFalse_shouldPassToFrameworkOnce() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getValue());
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verifyZeroInteractions(mMockPowerManagerService);
     }
 
@@ -349,9 +349,9 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getValue());
         assertEquals(1, mMessageCapturingHandler.timedMessages.size());
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
         verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
                 eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
     }
@@ -362,11 +362,11 @@
     @Test
     public void testFlushService_withPendingEvent_shouldPassToFramework() {
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.flush(mKeyEventFilter1);
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -377,7 +377,7 @@
         mKeyEventDispatcher.flush(mKeyEventFilter1);
         mKeyEventDispatcher.flush(mKeyEventFilter2);
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -389,7 +389,7 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, true,
                 mFilter2SequenceCaptor.getValue());
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -401,7 +401,7 @@
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
 
-        assertTrue(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertTrue(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -417,11 +417,11 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(0));
-        mInputEventsHander.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
+        mInputEventsHandler.removeMessages(SEND_FRAMEWORK_KEY_EVENT);
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(1));
 
@@ -433,14 +433,14 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(1));
 
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
     }
 
     @Test
@@ -448,7 +448,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
@@ -463,7 +463,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, false,
                 mFilter1SequenceCaptor.getAllValues().get(0));
@@ -478,9 +478,9 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher
                 .notifyKeyEventLocked(mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
-        mKeyEventDispatcher.handleMessage(mMessageCapturingHandler.timedMessages.get(0));
+        mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
                 mFilter1SequenceCaptor.getAllValues().get(0));
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter1, true,
@@ -494,7 +494,7 @@
         mKeyEventDispatcher.notifyKeyEventLocked(mKeyEvent, 0, Arrays.asList(mKeyEventFilter1));
         mKeyEventDispatcher.notifyKeyEventLocked(
                 mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter1, mKeyEventFilter2));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getValue());
@@ -513,7 +513,7 @@
         mKeyEventDispatcher.flush(mKeyEventFilter1);
         mKeyEventDispatcher.notifyKeyEventLocked(
                 mOtherKeyEvent, 0, Arrays.asList(mKeyEventFilter2));
-        assertFalse(mInputEventsHander.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
+        assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
 
         mKeyEventDispatcher.setOnKeyEventResult(mKeyEventFilter2, false,
                 mFilter2SequenceCaptor.getAllValues().get(0));
@@ -543,24 +543,34 @@
     }
 
     private void assertOneKeyEventSentToFramework(KeyEvent event) {
-        assertEquals(1, mInputEventsHander.timedMessages.size());
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(0).arg1);
-        assertTrue(new KeyEventMatcher(event).matches(mInputEventsHander.timedMessages.get(0).obj));
+        assertEquals(1, mInputEventsHandler.timedMessages.size());
+
+        Message m = getTimedMessage(mInputEventsHandler, 0);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m.arg1);
+        assertTrue(new KeyEventMatcher(event).matches(m.obj));
     }
 
     private void assertTwoKeyEventsSentToFrameworkInOrder(KeyEvent first, KeyEvent second) {
-        assertEquals(2, mInputEventsHander.timedMessages.size());
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(0).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(0).arg1);
-        assertTrue(new KeyEventMatcher(first).matches(mInputEventsHander.timedMessages.get(0).obj));
-        assertEquals(SEND_FRAMEWORK_KEY_EVENT, mInputEventsHander.timedMessages.get(1).what);
-        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER,
-                mInputEventsHander.timedMessages.get(1).arg1);
-        assertTrue(new KeyEventMatcher(second)
-                .matches(mInputEventsHander.timedMessages.get(1).obj));
+        assertEquals(2, mInputEventsHandler.timedMessages.size());
+
+        Message m0 = getTimedMessage(mInputEventsHandler, 0);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m0.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m0.arg1);
+        assertTrue(new KeyEventMatcher(first).matches(m0.obj));
+
+        Message m1 = getTimedMessage(mInputEventsHandler, 1);
+        assertEquals(SEND_FRAMEWORK_KEY_EVENT, m1.what);
+        assertEquals(WindowManagerPolicy.FLAG_PASS_TO_USER, m1.arg1);
+        assertTrue(new KeyEventMatcher(second).matches(m1.obj));
+    }
+
+    private static Message getTimedMessage(MessageCapturingHandler handler, int i) {
+        return handler.timedMessages.get(i).first;
+    }
+
+    private static boolean isTimeoutPending(MessageCapturingHandler handler) {
+        return handler.hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
     }
 
     private class KeyEventMatcher extends TypeSafeMatcher<KeyEvent> {
@@ -581,18 +591,4 @@
             description.appendText("Key event matcher");
         }
     }
-
-    private class MessageCapturingHandler extends Handler {
-        List<Message> timedMessages = new ArrayList<>();
-
-        @Override
-        public boolean sendMessageAtTime(Message message, long uptimeMillis) {
-            timedMessages.add(Message.obtain(message));
-            return super.sendMessageAtTime(message, uptimeMillis);
-        }
-
-        public boolean isTimeoutPending() {
-            return hasMessages(KeyEventDispatcher.MSG_ON_KEY_EVENT_TIMEOUT);
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
index 851e221..9926a09 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyboardInterceptorTest.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.when;
 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
 
-import android.os.Looper;
 import android.view.KeyEvent;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -38,8 +37,8 @@
 
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
@@ -58,19 +57,18 @@
     @Mock AccessibilityManagerService mMockAms;
     @Mock WindowManagerPolicy mMockPolicy;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mInterceptor = new KeyboardInterceptor(mMockAms, mMockPolicy, mHandler);
     }
 
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+
     @Test
     public void whenNonspecialKeyArrives_withNothingInQueue_eventGoesToAms() {
         KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
index d6d21c6..c88b873 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -43,9 +43,9 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.support.test.filters.FlakyTest;
 import android.view.MagnificationSpec;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
@@ -55,8 +55,8 @@
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -67,7 +67,6 @@
 import java.util.Locale;
 
 @RunWith(AndroidJUnit4.class)
-@FlakyTest
 public class MagnificationControllerTest {
     static final Rect INITIAL_MAGNIFICATION_BOUNDS = new Rect(0, 0, 100, 200);
     static final PointF INITIAL_MAGNIFICATION_BOUNDS_CENTER = new PointF(
@@ -75,8 +74,10 @@
     static final PointF INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER = new PointF(25, 50);
     static final PointF INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(75, 150);
     static final Rect OTHER_MAGNIFICATION_BOUNDS = new Rect(100, 200, 500, 600);
+    static final Rect OTHER_MAGNIFICATION_BOUNDS_COMPAT = new Rect(50, 100, 450, 500);
     static final PointF OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER = new PointF(400, 500);
     static final Region INITIAL_MAGNIFICATION_REGION = new Region(INITIAL_MAGNIFICATION_BOUNDS);
+    static final Region OTHER_REGION_COMPAT = new Region(OTHER_MAGNIFICATION_BOUNDS_COMPAT);
     static final Region OTHER_REGION = new Region(OTHER_MAGNIFICATION_BOUNDS);
     static final int SERVICE_ID_1 = 1;
     static final int SERVICE_ID_2 = 2;
@@ -91,25 +92,17 @@
             return mMagnificationController.handleMessage(msg);
         }
     });
-    final ArgumentCaptor<MagnificationSpec> mMagnificationSpecCaptor =
-            ArgumentCaptor.forClass(MagnificationSpec.class);
     final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class);
     MagnificationController.SettingsBridge mMockSettingsBridge;
 
-
     MagnificationController mMagnificationController;
     ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
-        when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper());
+        Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+        // Pretending ID of the Thread associated with looper as main thread ID in controller
+        when(mMockContext.getMainLooper()).thenReturn(looper);
         Resources mockResources = mock(Resources.class);
         when(mMockContext.getResources()).thenReturn(mockResources);
         when(mockResources.getInteger(R.integer.config_longAnimTime))
@@ -136,6 +129,12 @@
         Mockito.reset(mMockValueAnimator); // Ignore other initialization
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testRegister_WindowManagerAndContextRegisterListeners() {
         mMagnificationController.register();
@@ -202,6 +201,7 @@
         final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
         assertTrue(mMagnificationController
                 .setScale(scale, center.x, center.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets);
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
@@ -219,6 +219,7 @@
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
                 .setScale(scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         // New center should be halfway between original center and pivot
         PointF newCenter = new PointF((pivotPoint.x + INITIAL_MAGNIFICATION_BOUNDS.centerX()) / 2,
@@ -264,6 +265,7 @@
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
                 .setCenter(newCenter.x, newCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, expectedOffsets);
 
@@ -284,6 +286,7 @@
 
         assertTrue(mMagnificationController.setScaleAndCenter(scale, newCenter.x, newCenter.y,
                 true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -325,6 +328,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(
                 MagnificationController.MAX_SCALE + 1.0f,
                 newCenter.x, newCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -335,6 +339,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(0.5f,
                 INITIAL_MAGNIFICATION_BOUNDS_CENTER.x, INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
                 false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.x,
                 mMagnificationController.getCenterX(), 0.5);
@@ -351,6 +356,7 @@
         // Off the edge to the top and left
         assertTrue(mMagnificationController.setScaleAndCenter(
                 scale, -100f, -200f, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
         PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
@@ -364,6 +370,7 @@
         assertTrue(mMagnificationController.setScaleAndCenter(scale,
                 INITIAL_MAGNIFICATION_BOUNDS.right + 1, INITIAL_MAGNIFICATION_BOUNDS.bottom + 1,
                 false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
@@ -391,12 +398,14 @@
         // First zoom in
         assertTrue(mMagnificationController
                 .setScaleAndCenter(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
         Mockito.reset(mMockWindowManager);
 
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         mMagnificationController.offsetMagnifiedRegion(
                 startOffsets.x - newOffsets.x, startOffsets.y - newOffsets.y, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
 
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
@@ -490,6 +499,7 @@
     public void testResetIfNeeded_doesWhatItSays() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         reset(mMockAms);
         assertTrue(mMagnificationController.resetIfNeeded(false));
         verify(mMockAms).notifyMagnificationChanged(
@@ -507,6 +517,7 @@
                 broadcastReceiverCaptor.capture(), (IntentFilter) anyObject());
         BroadcastReceiver br = broadcastReceiverCaptor.getValue();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         br.onReceive(mMockContext, null);
         mMessageCapturingHandler.sendAllMessages();
         assertFalse(mMagnificationController.isMagnifying());
@@ -517,6 +528,7 @@
         mMagnificationController.register();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         callbacks.onUserContextChanged();
         mMessageCapturingHandler.sendAllMessages();
         assertFalse(mMagnificationController.isMagnifying());
@@ -539,10 +551,11 @@
         // Going from a small region to a large one leads to no issues
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
-        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
         assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
@@ -553,11 +566,12 @@
         mMagnificationController.register();
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
+        // setting animate parameter to true is differ from zoomIn2xToMiddle()
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
-        callbacks.onMagnificationRegionChanged(OTHER_REGION);
+        callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
         assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
@@ -573,6 +587,7 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
         Mockito.reset(mMockWindowManager);
@@ -597,8 +612,9 @@
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
         mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        when (mMockValueAnimator.isRunning()).thenReturn(true);
+        when(mMockValueAnimator.isRunning()).thenReturn(true);
 
         callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
         mMessageCapturingHandler.sendAllMessages();
@@ -616,6 +632,7 @@
     public void testRequestRectOnScreen_rectAlreadyOnScreen_doesNothing() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
@@ -631,6 +648,7 @@
     public void testRequestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
         callbacks.onRectangleOnScreenRequested(0, 0, 1, 1);
@@ -644,6 +662,7 @@
     public void testRequestRectOnScreen_garbageInput_doesNothing() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         Mockito.reset(mMockWindowManager);
@@ -653,12 +672,12 @@
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
-
     @Test
     public void testRequestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale() {
         Locale.setDefault(new Locale("en", "us"));
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         Mockito.reset(mMockWindowManager);
@@ -685,6 +704,7 @@
     public void testRequestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen() {
         mMagnificationController.register();
         zoomIn2xToMiddle();
+        mMessageCapturingHandler.sendAllMessages();
         MagnificationCallbacks callbacks = getMagnificationCallbacks();
         MagnificationSpec startSpec = getCurrentMagnificationSpec();
         Mockito.reset(mMockWindowManager);
@@ -708,6 +728,7 @@
 
         assertTrue(mMagnificationController.setScaleAndCenter(scale, firstCenter.x, firstCenter.y,
                 true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         assertEquals(firstCenter.x, mMagnificationController.getCenterX(), 0.5);
         assertEquals(firstCenter.y, mMagnificationController.getCenterY(), 0.5);
@@ -736,6 +757,7 @@
                 scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale));
         assertTrue(mMagnificationController.setCenter(
                 newCenter.x, newCenter.y, true, SERVICE_ID_1));
+        mMessageCapturingHandler.sendAllMessages();
 
         // Animation should have been restarted
         verify(mMockValueAnimator, times(2)).start();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
index e3ee47f..e2b517f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MessageCapturingHandler.java
@@ -16,11 +16,13 @@
 
 package com.android.server.accessibility;
 
-import android.app.Notification;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -34,13 +36,22 @@
     Handler.Callback mCallback;
 
     public MessageCapturingHandler(Handler.Callback callback) {
+        this(InstrumentationRegistry.getContext().getMainLooper(), callback);
+    }
+
+    public MessageCapturingHandler(Looper looper, Callback callback) {
+        super(looper);
         mCallback = callback;
     }
 
+    /**
+     * Holding messages in queue, but never dispatching.
+     * @see #removeAllMessages()
+     */
     @Override
     public boolean sendMessageAtTime(Message message, long uptimeMillis) {
         timedMessages.add(new Pair<>(Message.obtain(message), uptimeMillis));
-        return super.sendMessageAtTime(message, uptimeMillis);
+        return super.sendMessageAtTime(message, Long.MAX_VALUE);
     }
 
     public void setCallback(Handler.Callback callback) {
@@ -67,6 +78,22 @@
         removeStaleMessages();
     }
 
+    /**
+     * Clear messages sent from this handler in queue.
+     * <p>
+     * If main looper is used, this method should be called in tear down function
+     * to ensure messages isolation between test cases.
+     * </p>
+     */
+    public void removeAllMessages() {
+        if (hasMessages()) {
+            for (int i = 0; i < timedMessages.size(); i++) {
+                Message message = timedMessages.get(i).first;
+                removeMessages(message.what, message.obj);
+            }
+        }
+    }
+
     public boolean hasMessages() {
         removeStaleMessages();
         return !timedMessages.isEmpty();
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 5f0fa87..2cba9d0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -43,7 +43,6 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.graphics.Point;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
@@ -57,8 +56,8 @@
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -127,13 +126,6 @@
     Matcher<MotionEvent> mIsClickDown;
     Matcher<MotionEvent> mIsClickUp;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setUp() {
         mMessageCapturingHandler = new MessageCapturingHandler(new Handler.Callback() {
@@ -172,6 +164,12 @@
                 hasTimeFromDown(CLICK_DURATION));
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void testInjectEvents_shouldEmergeInOrderWithCorrectTiming() throws RemoteException {
         EventStreamTransformation next = attachMockNext(mMotionEventInjector);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
index c47885f..2645461 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/TouchExplorerTest.java
@@ -16,12 +16,14 @@
 
 package com.android.server.accessibility;
 
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.os.SystemClock;
+import android.testing.DexmakerShareClassLoaderRule;
 import android.util.DebugUtils;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -30,6 +32,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -66,6 +69,11 @@
     private TouchExplorer mTouchExplorer;
     private long mLastDownTime = Integer.MIN_VALUE;
 
+    // mock package-private AccessibilityGestureDetector class
+    @Rule
+    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+            new DexmakerShareClassLoaderRule();
+
     /**
      * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
      * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
@@ -93,8 +101,9 @@
     public void setUp() {
         Context context = InstrumentationRegistry.getContext();
         AccessibilityManagerService ams = new AccessibilityManagerService(context);
+        AccessibilityGestureDetector detector = mock(AccessibilityGestureDetector.class);
         mCaptor = new EventCaptor();
-        mTouchExplorer = new TouchExplorer(context, ams);
+        mTouchExplorer = new TouchExplorer(context, ams, detector);
         mTouchExplorer.setNext(mCaptor);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 8853db2..8e09d60 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -32,13 +32,12 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.IBinder;
-import android.os.Looper;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.server.wm.WindowManagerInternal;
 
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -66,13 +65,6 @@
     @Mock IAccessibilityServiceClient mMockAccessibilityServiceClient;
     @Mock IBinder mMockServiceAsBinder;
 
-    @BeforeClass
-    public static void oneTimeInitialization() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -88,6 +80,12 @@
         mMessageCapturingHandler = new MessageCapturingHandler(null);
     }
 
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+
     @Test
     public void isRunning_returnsTrueOnlyWhenRunning() {
         assertFalse(mUiAutomationManager.isUiAutomationRunningLocked());
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d94a5f345..16b127c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -57,7 +57,6 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.PasswordMetrics;
-import android.app.backup.ISelectBackupTransportCallback;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -2251,8 +2250,8 @@
         assertEquals(UserManager.DISALLOW_ADJUST_VOLUME,
                 intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
 
-        // Try with POLICY_DISABLE_CAMERA, POLICY_DISABLE_SCREEN_CAPTURE and
-        // POLICY_MANDATORY_BACKUPS, which are not user restrictions
+        // Try with POLICY_DISABLE_CAMERA and POLICY_DISABLE_SCREEN_CAPTURE, which are not
+        // user restrictions
 
         // Camera is not disabled
         intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_CAMERA);
@@ -2276,34 +2275,6 @@
         assertEquals(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE,
                 intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
 
-        // Make the backup transport selection succeed
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                ISelectBackupTransportCallback callback =
-                    (ISelectBackupTransportCallback) invocation.getArguments()[1];
-                if (callback != null) {
-                    callback.onSuccess("");
-                }
-                return null;
-            }
-        }).when(getServices().ibackupManager).selectBackupTransportAsync(
-                any(ComponentName.class), any(ISelectBackupTransportCallback.class));
-
-
-        // Backups are not mandatory
-        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_MANDATORY_BACKUPS);
-        assertNull(intent);
-
-        // Backups are mandatory
-        ComponentName transportComponent = ComponentName.unflattenFromString(
-                "android/com.android.internal.backup.LocalTransport");
-        dpm.setMandatoryBackupTransport(admin1, transportComponent);
-        intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_MANDATORY_BACKUPS);
-        assertNotNull(intent);
-        assertEquals(DevicePolicyManager.POLICY_MANDATORY_BACKUPS,
-                intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION));
-
         // Same checks for different user
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
         // Camera should be disabled by device owner
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
similarity index 97%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 8a83518..910d433 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -23,15 +23,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
-import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
-import com.android.internal.inputmethod.InputMethodUtils;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
similarity index 99%
rename from core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index f731a4a..4d0278f 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
 import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;
@@ -37,13 +37,14 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
similarity index 76%
rename from core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
rename to services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
index 7d0e646..3fc0e4f 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/LocaleUtilsTest.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.inputmethod;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,18 +35,6 @@
 
     private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper = source -> source;
 
-    private static final Locale LOCALE_EN = new Locale("en");
-    private static final Locale LOCALE_EN_US = new Locale("en", "US");
-    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
-    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
-    private static final Locale LOCALE_FIL = new Locale("fil");
-    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
-    private static final Locale LOCALE_JA = new Locale("ja");
-    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
-    private static final Locale LOCALE_TH = new Locale("ht");
-    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
-    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
-
     @Test
     public void testFilterByLanguageEmptyLanguageList() throws Exception {
         final ArrayList<Locale> availableLocales = new ArrayList<>();
@@ -398,120 +386,4 @@
             assertEquals(availableLocales.get(3), dest.get(0));
         }
     }
-
-    @Test
-    public void testGetSuitableLocalesForSpellChecker() throws Exception {
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_US, locales.get(0));
-            assertEquals(LOCALE_EN_GB, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_GB, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
-            assertEquals(4, locales.size());
-            assertEquals(LOCALE_EN_IN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-            assertEquals(LOCALE_EN, locales.get(3));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test 3-letter language code.
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_FIL_PH, locales.get(0));
-            assertEquals(LOCALE_FIL, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test variant.
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
-            assertEquals(6, locales.size());
-            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
-            assertEquals(LOCALE_TH_TH, locales.get(1));
-            assertEquals(LOCALE_TH, locales.get(2));
-            assertEquals(LOCALE_EN_US, locales.get(3));
-            assertEquals(LOCALE_EN_GB, locales.get(4));
-            assertEquals(Locale.ENGLISH, locales.get(5));
-        }
-
-        // Test Locale extension.
-        {
-            final Locale localeWithoutVariant = LOCALE_JA_JP;
-            final Locale localeWithVariant = new Locale.Builder()
-                    .setLocale(LOCALE_JA_JP)
-                    .setExtension('x', "android")
-                    .build();
-            assertFalse(localeWithoutVariant.equals(localeWithVariant));
-
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-    }
-
-    @Test
-    public void testConstructLocaleFromString() throws Exception {
-        assertEquals(new Locale("en"), LocaleUtils.constructLocaleFromString("en"));
-        assertEquals(new Locale("en", "US"), LocaleUtils.constructLocaleFromString("en_US"));
-        assertEquals(new Locale("en", "US", "POSIX"),
-                LocaleUtils.constructLocaleFromString("en_US_POSIX"));
-
-        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
-        // support three letter language codes, and used "tl" (Tagalog) as the language string for
-        // "fil" (Filipino).
-        assertEquals(new Locale("fil"), LocaleUtils.constructLocaleFromString("tl"));
-        assertEquals(new Locale("fil", "PH"), LocaleUtils.constructLocaleFromString("tl_PH"));
-        assertEquals(new Locale("fil", "PH", "POSIX"),
-                LocaleUtils.constructLocaleFromString("tl_PH_POSIX"));
-
-        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
-        assertEquals(new Locale("a"), LocaleUtils.constructLocaleFromString("a"));
-        assertEquals(new Locale("a b c"), LocaleUtils.constructLocaleFromString("a b c"));
-        assertEquals(new Locale("en-US"), LocaleUtils.constructLocaleFromString("en-US"));
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ee41c0b..c3c0788 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -716,9 +716,9 @@
         assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
         assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
         assertThat(origPkgSetting.name, is(testPkgSetting.name));
-        // oldCodePaths is _not_ copied
-        // assertNotSame(origPkgSetting.oldCodePaths, testPkgSetting.oldCodePaths);
-        // assertThat(origPkgSetting.oldCodePaths, is(not(testPkgSetting.oldCodePaths)));
+        // mOldCodePaths is _not_ copied
+        // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
+        // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
         assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
         assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
         assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
diff --git a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
similarity index 95%
rename from core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
rename to services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
index 3518527..f80afb2 100644
--- a/core/tests/coretests/src/com/android/internal/textservice/LazyIntToIntMapTest.java
+++ b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.textservice;
+package com.android.server.textservices;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -25,8 +25,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java
new file mode 100644
index 0000000..3766d24
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textservices/LocaleUtilsTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.server.textservices;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+public class LocaleUtilsTest {
+    private static final Locale LOCALE_EN = new Locale("en");
+    private static final Locale LOCALE_EN_US = new Locale("en", "US");
+    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
+    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_JA = new Locale("ja");
+    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
+    private static final Locale LOCALE_TH = new Locale("ht");
+    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
+    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
+
+    @Test
+    public void testGetSuitableLocalesForSpellChecker() throws Exception {
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_US, locales.get(0));
+            assertEquals(LOCALE_EN_GB, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_GB, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
+            assertEquals(4, locales.size());
+            assertEquals(LOCALE_EN_IN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+            assertEquals(LOCALE_EN, locales.get(3));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test 3-letter language code.
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_FIL_PH, locales.get(0));
+            assertEquals(LOCALE_FIL, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test variant.
+        {
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
+            assertEquals(6, locales.size());
+            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
+            assertEquals(LOCALE_TH_TH, locales.get(1));
+            assertEquals(LOCALE_TH, locales.get(2));
+            assertEquals(LOCALE_EN_US, locales.get(3));
+            assertEquals(LOCALE_EN_GB, locales.get(4));
+            assertEquals(Locale.ENGLISH, locales.get(5));
+        }
+
+        // Test Locale extension.
+        {
+            final Locale localeWithoutVariant = LOCALE_JA_JP;
+            final Locale localeWithVariant = new Locale.Builder()
+                    .setLocale(LOCALE_JA_JP)
+                    .setExtension('x', "android")
+                    .build();
+            assertFalse(localeWithoutVariant.equals(localeWithVariant));
+
+            final ArrayList<Locale> locales =
+                    LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 9fa5ba4..ea44279 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -109,4 +109,22 @@
         assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
         assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack);
     }
+
+    @Test
+    public void testDisplayPositionWithPinnedStack() {
+        // The display contains pinned stack that was added in {@link #setUp}.
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+
+        // Add another display at top.
+        sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+                false /* includingParents */);
+
+        // Move the task of {@code mDisplayContent} to top.
+        stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+        final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent);
+
+        assertEquals("The testing DisplayContent should be moved to top with task",
+                sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 5db0867..70e4ce4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -125,7 +125,7 @@
             synchronized (sWm.mWindowMap) {
                 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
                 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
-                sWm.mInputMethodWindow = mImeWindow;
+                mDisplayContent.mInputMethodWindow = mImeWindow;
                 mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
                         "mImeDialogWindow");
                 mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a1b3b98..4344285 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -519,8 +519,9 @@
         NotificationChannel channel = new NotificationChannel("id", "name",
                 IMPORTANCE_HIGH);
         NotificationRecord r = generateNotificationRecord(channel);
-        assertTrue(mService.isBlocked(r, mUsageStats));
-        verify(mUsageStats, times(1)).registerSuspendedByAdmin(eq(r));
+
+        // isBlocked is only used for user blocking, not app suspension
+        assertFalse(mService.isBlocked(r, mUsageStats));
     }
 
     @Test
@@ -3453,4 +3454,46 @@
             // yay
         }
     }
+
+    @Test
+    public void testRemoveForegroundServiceFlagFromNotification_enqueued() {
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
+                n, new UserHandle(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addEnqueuedNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.sbn.getId(), r.sbn.getUserId());
+
+        waitForIdle();
+
+        verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any());
+    }
+
+    @Test
+    public void testRemoveForegroundServiceFlagFromNotification_posted() {
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
+                n, new UserHandle(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.sbn.getId(), r.sbn.getUserId());
+
+        waitForIdle();
+
+        ArgumentCaptor<NotificationRecord> captor =
+                ArgumentCaptor.forClass(NotificationRecord.class);
+        verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any());
+
+        assertEquals(0, captor.getValue().getNotification().flags);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
new file mode 100644
index 0000000..100f9c6
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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 distriZenbuted 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.NotificationManager.Policy;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenModeConfigTest extends UiServiceTestCase {
+
+    @Test
+    public void testPriorityOnlyMutingAllNotifications() {
+        ZenModeConfig config = getMutedNotificationsConfig();
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+
+        config.allowReminders = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        config.allowReminders = false;
+
+        config.areChannelsBypassingDnd = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        config.areChannelsBypassingDnd = false;
+
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+    }
+
+    @Test
+    public void testZenPolicyNothingSetToNotificationPolicy() {
+        ZenModeConfig config = getMutedAllConfig();
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().build();
+        assertEquals(config.toNotificationPolicy(), config.toNotificationPolicy(zenPolicy));
+    }
+
+    @Test
+    public void testZenPolicyToNotificationPolicy() {
+        ZenModeConfig config = getMutedAllConfig();
+        config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+
+        ZenPolicy zenPolicy = new ZenPolicy.Builder()
+                .allowAlarms(true)
+                .allowReminders(true)
+                .allowEvents(true)
+                .showLights(false)
+                .showInAmbientDisplay(false)
+                .build();
+
+        Policy originalPolicy = config.toNotificationPolicy();
+        int priorityCategories = originalPolicy.priorityCategories;
+        int priorityCallSenders = originalPolicy.priorityCallSenders;
+        int priorityMessageSenders = originalPolicy.priorityMessageSenders;
+        int suppressedVisualEffects = originalPolicy.suppressedVisualEffects;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
+        priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+        suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+
+        Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
+                priorityMessageSenders, suppressedVisualEffects);
+
+        assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
+    }
+
+    @Test
+    public void testPriorityOnlyMutingAll() {
+        ZenModeConfig config = getMutedAllConfig();
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+
+        config.allowReminders = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.allowReminders = false;
+
+        config.areChannelsBypassingDnd = true;
+        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.areChannelsBypassingDnd = false;
+
+        config.allowAlarms = true;
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        config.allowAlarms = false;
+
+        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+    }
+
+    private ZenModeConfig getMutedNotificationsConfig() {
+        ZenModeConfig config = new ZenModeConfig();
+        // Allow alarms, media, and system
+        config.allowAlarms = true;
+        config.allowMedia = true;
+        config.allowSystem = true;
+
+        // All notification sounds are not allowed
+        config.allowCalls = false;
+        config.allowRepeatCallers = false;
+        config.allowMessages = false;
+        config.allowReminders = false;
+        config.allowEvents = false;
+        config.areChannelsBypassingDnd = false;
+
+        config.suppressedVisualEffects = 0;
+
+        return config;
+    }
+
+    private ZenModeConfig getMutedAllConfig() {
+        ZenModeConfig config = new ZenModeConfig();
+        // No sounds allowed
+        config.allowAlarms = false;
+        config.allowMedia = false;
+        config.allowSystem = false;
+        config.allowCalls = false;
+        config.allowRepeatCallers = false;
+        config.allowMessages = false;
+        config.allowReminders = false;
+        config.allowEvents = false;
+        config.areChannelsBypassingDnd = false;
+
+        config.suppressedVisualEffects = 0;
+        return config;
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
new file mode 100644
index 0000000..7c6b1c1
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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 distriZenbuted 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.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.service.notification.ZenPolicy;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenPolicyTest extends UiServiceTestCase {
+
+    @Test
+    public void testZenPolicyApplyAllowedToDisallowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+        assertEquals(ZenPolicy.STATE_ALLOW,
+                remindersAllowed.getPriorityCategoryReminders());
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+
+        // we apply reminders allowed to reminders disallowed
+        // -> reminders should remain disallowed
+        remindersDisallowed.apply(remindersAllowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersDisallowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyAllowedToUnset() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are unset
+        ZenPolicy remindersUnset = builder.build();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // we apply reminders allowed to reminders unset
+        // -> reminders should be allowed
+        remindersUnset.apply(remindersAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, remindersUnset.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyDisallowedToUnset() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are unset
+        ZenPolicy remindersUnset = builder.build();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+
+        // we apply reminders disallowed to reminders unset
+        // -> reminders should remain disallowed
+        remindersUnset.apply(remindersDisallowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW,
+                remindersUnset.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyDisallowedToAllowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // reminders are disallowed
+        builder.allowReminders(false);
+        ZenPolicy remindersDisallowed = builder.build();
+
+        // we apply reminders allowed to reminders disallowed
+        // -> reminders should change to disallowed
+        remindersAllowed.apply(remindersDisallowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW, remindersAllowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyUnsetToAllowed() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // reminders are allowed
+        builder.allowReminders(true);
+        ZenPolicy remindersAllowed = builder.build();
+
+        // reminders are unset
+        ZenPolicy.Builder builder2 = new ZenPolicy.Builder();
+        ZenPolicy remindersUnset = builder2.build();
+
+        // we apply reminders allowed to reminders unset
+        // -> reminders should remain allowed
+        remindersAllowed.apply(remindersUnset);
+        assertEquals(ZenPolicy.STATE_ALLOW, remindersAllowed.getPriorityCategoryReminders());
+    }
+
+    @Test
+    public void testZenPolicyApplyMoreSevereCallSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // calls from contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // calls from starred contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+        ZenPolicy starredAllowed = builder.build();
+
+        // we apply starredAllowed to contactsAllowed -> starred contacts allowed (more restrictive)
+        contactsAllowed.apply(starredAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, contactsAllowed.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testZenPolicyApplyLessSevereCallSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // calls from contacts allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // calls from anyone allowed
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy anyoneAllowed = builder.build();
+
+        // we apply anyoneAllowed to contactsAllowed -> contactsAllowed (more restrictive)
+        contactsAllowed.apply(anyoneAllowed);
+        assertEquals(ZenPolicy.STATE_ALLOW, contactsAllowed.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, contactsAllowed.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testZenPolicyApplyMoreSevereMessageSenders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        // messsages from contacts allowed
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        ZenPolicy contactsAllowed = builder.build();
+
+        // messsages from no one allowed
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+        ZenPolicy noneAllowed = builder.build();
+
+        // noneAllowed to contactsAllowed -> no messages allowed (more restrictive)
+        contactsAllowed.apply(noneAllowed);
+        assertEquals(ZenPolicy.STATE_DISALLOW, contactsAllowed.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, contactsAllowed.getPriorityMessageSenders());
+    }
+
+    @Test
+    public void testZenPolicyMessagesInvalid() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMessages(20); // invalid #, won't change policy
+        ZenPolicy policy = builder.build();
+        assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders());
+    }
+
+    @Test
+    public void testZenPolicyCallsInvalid() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        builder.allowCalls(20); // invalid #, won't change policy
+        ZenPolicy policy = builder.build();
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+    }
+
+    @Test
+    public void testEmptyZenPolicy() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowReminders() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowReminders(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowReminders(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowEvents() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowEvents(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowEvents(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowMessages() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MESSAGES);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowCalls() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_ANYONE);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_CALLS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls());
+        assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, -1);
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowRepeatCallers() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowRepeatCallers(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowRepeatCallers(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowAlarms() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowAlarms(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowAlarms(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowMedia() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowMedia(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowMedia(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    @Test
+    public void testAllowSystem() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.allowSystem(true);
+        ZenPolicy policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+        assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+
+        builder.allowSystem(false);
+        policy = builder.build();
+        assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
+        assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem());
+        assertAllVisualEffectsUnsetExcept(policy, -1);
+    }
+
+    private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
+        if (except != ZenPolicy.PRIORITY_CATEGORY_REMINDERS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryReminders());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_EVENTS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryEvents());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_MESSAGES) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_CALLS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryCalls());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryRepeatCallers());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_ALARMS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryAlarms());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_MEDIA) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMedia());
+        }
+
+        if (except != ZenPolicy.PRIORITY_CATEGORY_SYSTEM) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategorySystem());
+        }
+    }
+
+    private void assertAllVisualEffectsUnsetExcept(ZenPolicy policy, int except) {
+        if (except != ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectFullScreenIntent());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_LIGHTS) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectLights());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_PEEK) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectPeek());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_STATUS_BAR) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectStatusBar());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_BADGE) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectBadge());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_AMBIENT) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectAmbient());
+        }
+
+        if (except != ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST) {
+            assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList());
+        }
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 589bcdc..cf47ad3 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -40,6 +40,7 @@
 import com.android.server.usb.descriptors.UsbDescriptor;
 import com.android.server.usb.descriptors.UsbDescriptorParser;
 import com.android.server.usb.descriptors.UsbDeviceDescriptor;
+import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
 import com.android.server.usb.descriptors.report.TextReportCanvas;
 import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
 
@@ -352,8 +353,6 @@
             }
             return false;
         }
-        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
-        logUsbDevice(parser);
 
         if (isBlackListed(deviceClass, deviceSubclass)) {
             if (DEBUG) {
@@ -362,6 +361,15 @@
             return false;
         }
 
+        UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
+        if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE
+                && !checkUsbInterfacesBlackListed(parser)) {
+            return false;
+        }
+
+        // Potentially can block as it may read data from the USB device.
+        logUsbDevice(parser);
+
         synchronized (mLock) {
             if (mDevices.get(deviceAddress) != null) {
                 Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
@@ -513,6 +521,29 @@
         }
     }
 
+    private boolean checkUsbInterfacesBlackListed(UsbDescriptorParser parser) {
+        // Device class needs to be obtained through the device interface.  Ignore device only
+        // if ALL interfaces are black-listed.
+        boolean shouldIgnoreDevice = false;
+        for (UsbDescriptor descriptor: parser.getDescriptors()) {
+            if (!(descriptor instanceof UsbInterfaceDescriptor)) {
+                continue;
+            }
+            UsbInterfaceDescriptor iface = (UsbInterfaceDescriptor) descriptor;
+            shouldIgnoreDevice = isBlackListed(iface.getUsbClass(), iface.getUsbSubclass());
+            if (!shouldIgnoreDevice) {
+                break;
+            }
+        }
+        if (shouldIgnoreDevice) {
+            if (DEBUG) {
+                Slog.d(TAG, "usb interface class is black listed");
+            }
+            return false;
+        }
+        return true;
+    }
+
     private native void monitorUsbHostBus();
     private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
 }
diff --git a/startop/OWNERS b/startop/OWNERS
new file mode 100644
index 0000000..bfe96d3
--- /dev/null
+++ b/startop/OWNERS
@@ -0,0 +1,5 @@
+# mailing list: startop-eng@google.com
+chriswailes@google.com
+eholk@google.com
+iam@google.com
+sehr@google.com
diff --git a/startop/scripts/app_startup/analyze_metrics.py b/startop/scripts/app_startup/analyze_metrics.py
new file mode 100755
index 0000000..d74d6f6
--- /dev/null
+++ b/startop/scripts/app_startup/analyze_metrics.py
@@ -0,0 +1,457 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+
+"""
+Perform statistical analysis on measurements produced by app_startup_runner.py
+
+Install:
+$> sudo apt-get install python3-scipy
+
+Usage:
+$> ./analyze_metrics.py <filename.csv> [<filename2.csv> ...]
+$> ./analyze_metrics.py --help
+"""
+
+import argparse
+import csv
+import itertools
+import os
+import subprocess
+import sys
+import tempfile
+from typing import Any, List, Dict, Iterable, TextIO, Tuple
+
+from scipy import stats as sc
+import numpy as np
+
+
+# These CSV columns are considered labels. Everything after them in the same row are metrics.
+_LABEL_COLUMNS=['packages', 'readaheads', 'compiler_filters']
+# The metric series with the 'cold' readahead is the baseline.
+# All others (warm, jit, etc) are the potential improvements.
+
+#fixme: this should probably be an option
+_BASELINE=('readaheads', 'cold')
+# ignore this for some statistic calculations
+_IGNORE_PAIR=('readaheads', 'warm')
+_PLOT_SUBKEY='readaheads'
+_PLOT_GROUPKEY='packages'
+_PLOT_DATA_INDEX = 0
+_DELTA=50
+_DELTA2=100
+_PVALUE_THRESHOLD=0.10
+_debug = False  # See -d/--debug flag.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Perform statistical analysis on measurements produced by app_start_runner.py.")
+  parser.add_argument('input_files', metavar='file.csv', nargs='+', help='CSV file produced by app_startup_runner.py')
+
+  parser.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+  parser.add_argument('-os', '--output-samples', dest='output_samples', default='/dev/null', action='store', help='Store CSV for per-sample data')
+  parser.add_argument('-oc', '--output-comparable', dest='output_comparable', default='/dev/null', action='store', help='Output CSV for comparable against baseline')
+  parser.add_argument('-ocs', '--output-comparable-significant', dest='output_comparable_significant', default='/dev/null', action='store', help='Output CSV for comparable against baseline (significant only)')
+  parser.add_argument('-pt', '--pvalue-threshold', dest='pvalue_threshold', type=float, default=_PVALUE_THRESHOLD, action='store')
+  parser.add_argument('-dt', '--delta-threshold', dest='delta_threshold', type=int, default=_DELTA, action='store')
+
+  return parser.parse_args(argv)
+
+def _debug_print(*args, **kwargs):
+  """Print the args to sys.stderr if the --debug/-d flag was passed in."""
+  global _debug
+  if _debug:
+    print(*args, **kwargs, file=sys.stderr)
+
+def _expand_gen_repr(args):
+  new_args_list = []
+  for i in args:
+    # detect iterable objects that do not have their own override of __str__
+    if hasattr(i, '__iter__'):
+      to_str = getattr(i, '__str__')
+      if to_str.__objclass__ == object:
+        # the repr for a generator is just type+address, expand it out instead.
+        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
+        continue
+    # normal case: uses the built-in to-string
+    new_args_list.append(i)
+  return new_args_list
+
+def _debug_print_gen(*args, **kwargs):
+  """Like _debug_print but will turn any iterable args into a list."""
+  if not _debug:
+    return
+
+  new_args_list = _expand_gen_repr(args)
+  _debug_print(*new_args_list, **kwargs)
+
+def read_headers(input_file: TextIO) -> Tuple[List[str], List[str]]:
+  _debug_print("read_headers for file: ", input_file.name)
+  csv_reader = csv.reader(input_file)
+
+  label_num_columns = len(_LABEL_COLUMNS)
+
+  try:
+    header = next(csv_reader)
+  except StopIteration:
+    header = None
+  _debug_print('header', header)
+
+  if not header:
+    return (None, None)
+
+  labels = header[0:label_num_columns]
+  data = header[label_num_columns:]
+
+  return (labels, data)
+
+def read_labels_and_data(input_file: TextIO) -> Iterable[Tuple[List[str], List[int]]]:
+  _debug_print("print_analysis for file: ", input_file.name)
+  csv_reader = csv.reader(input_file)
+
+  # Skip the header because it doesn't contain any data.
+  # To get the header see read_headers function.
+  try:
+    header = next(csv_reader)
+  except StopIteration:
+    header = None
+
+  label_num_columns = len(_LABEL_COLUMNS)
+
+  for row in csv_reader:
+    if len(row) > 0 and row[0][0] == ';':
+      _debug_print("skip comment line", row)
+      continue
+
+    labels = row[0:label_num_columns]
+    data = [int(i) for i in row[label_num_columns:]]
+
+#    _debug_print("labels:", labels)
+#    _debug_print("data:", data)
+
+    yield (labels, data)
+
+def group_metrics_by_label(it: Iterable[Tuple[List[str], List[int]]]):
+  prev_labels = None
+  data_2d = []
+
+  for label_list, data_list in it:
+    if prev_labels != label_list:
+      if prev_labels:
+#        _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d)
+        yield (prev_labels, data_2d)
+      data_2d = []
+
+    data_2d.append(data_list)
+    prev_labels = label_list
+
+  if prev_labels:
+#    _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d)
+    yield (prev_labels, data_2d)
+
+def data_to_numpy(it: Iterable[Tuple[List[str], List[List[int]]]]) -> Iterable[Tuple[List[str], Any]]:
+  for label_list, data_2d in it:
+    yield (label_list, np.asarray(data_2d, dtype=int))
+
+def iterate_columns(np_data_2d):
+  for col in range(np_data_2d.shape[1]):
+    col_as_array = np_data_2d[:, col]
+    yield col_as_array
+
+def confidence_interval(np_data_2d, percent=0.95):
+  """
+  Given some data [[a,b,c],[d,e,f,]...]
+
+  We assume the same metric is in the column (e.g. [a,d])
+  and that data in the rows (e.g. [b,e]) are separate metric values.
+
+  We then calculate the CI for each metric individually returning it as a list of tuples.
+  """
+  arr = []
+  for col_2d in iterate_columns(np_data_2d):
+    mean = col_2d.mean()
+    sigma = col_2d.std()
+
+    ci = sc.norm.interval(percent, loc=mean, scale=sigma / np.sqrt(len(col_2d)))
+    arr.append(ci)
+
+  # TODO: This seems to be returning NaN when all the samples have the same exact value
+  # (e.g. stddev=0, which can trivially happen when sample count = 1).
+
+  return arr
+
+def print_analysis(it, label_header: List[str], data_header: List[str], output_samples: str):
+  print(label_header)
+
+  with open(output_samples, "w") as output_file:
+
+    csv_writer = csv.writer(output_file)
+    csv_writer.writerow(label_header + ['mean', 'std', 'confidence_interval_a', 'confidence_interval_b'])
+
+    for label_list, np_data_2d in it:
+      print("**********************")
+      print(label_list)
+      print()
+      print("      ", data_header)
+      # aggregate computation column-wise
+      print("Mean: ", np_data_2d.mean(axis=0))
+      print("Std:  ", np_data_2d.std(axis=0))
+      print("CI95%:", confidence_interval(np_data_2d))
+      print("SEM:  ", stats_standard_error_one(np_data_2d, axis=0))
+
+      #ci = confidence_interval(np_data_2d)[_PLOT_DATA_INDEX]
+      sem = stats_standard_error_one(np_data_2d, axis=0)[_PLOT_DATA_INDEX]
+      mean = np_data_2d.mean(axis=0)[_PLOT_DATA_INDEX]
+
+      ci = (mean - sem, mean + sem)
+
+      csv_writer.writerow(label_list + [mean, np_data_2d.std(axis=0)[_PLOT_DATA_INDEX], ci[0], ci[1]])
+
+def from_file_group_by_labels(input_file):
+  (label_header, data_header) = read_headers(input_file)
+  label_data_iter = read_labels_and_data(input_file)
+  grouped_iter = group_metrics_by_label(label_data_iter)
+  grouped_numpy_iter = data_to_numpy(grouped_iter)
+
+  return grouped_numpy_iter, label_header, data_header
+
+def list_without_index(list, index):
+  return list[:index] + list[index+1:]
+
+def group_by_without_baseline_key(grouped_numpy_iter, label_header):
+  """
+  Data is considered comparable if the only difference is the baseline key
+  (i.e. the readahead is different but the package, compilation filter, etc, are the same).
+
+  Returns iterator that's grouped by the non-baseline labels to an iterator of
+  (label_list, data_2d).
+  """
+  baseline_index = label_header.index(_BASELINE[0])
+
+  def get_label_without_baseline(tpl):
+    label_list, _ = tpl
+    return list_without_index(label_list, baseline_index)
+  # [['pkgname', 'compfilter', 'warm'], [data]]
+  # [['pkgname', 'compfilter', 'cold'], [data2]]
+  # [['pkgname2', 'compfilter', 'warm'], [data3]]
+  #
+  #   ->
+  # ( [['pkgname', 'compfilter', 'warm'], [data]]      # ignore baseline label change.
+  #   [['pkgname', 'compfilter', 'cold'], [data2]] ),  # split here because the pkgname changed.
+  # ( [['pkgname2', 'compfilter', 'warm'], [data3]] )
+  for group_info, it in itertools.groupby(grouped_numpy_iter, key = get_label_without_baseline):
+    yield it
+
+  # TODO: replace this messy manual iteration/grouping with pandas
+
+def iterate_comparable_metrics(without_baseline_iter, label_header):
+  baseline_index = label_header.index(_BASELINE[0])
+  baseline_value = _BASELINE[1]
+
+  _debug_print("iterate comparables")
+
+  def is_baseline_fun(tp):
+    ll, dat = tp
+    return ll[baseline_index] == baseline_value
+
+  # iterating here when everything but the baseline key is the same.
+  for it in without_baseline_iter:
+    it1, it2 = itertools.tee(it)
+
+    # find all the baseline data.
+    baseline_filter_it = filter(is_baseline_fun, it1)
+
+    # find non-baseline data.
+    nonbaseline_filter_it = itertools.filterfalse(is_baseline_fun, it2)
+
+    yield itertools.product(baseline_filter_it, nonbaseline_filter_it)
+
+def stats_standard_error_one(a, axis):
+  a_std = a.std(axis=axis, ddof=0)
+  a_len = a.shape[axis]
+
+  return a_std / np.sqrt(a_len)
+
+def stats_standard_error(a, b, axis):
+  a_std = a.std(axis=axis, ddof=0)
+  b_std = b.std(axis=axis, ddof=0)
+
+  a_len = a.shape[axis]
+  b_len = b.shape[axis]
+
+  temp1 = a_std*a_std/a_len
+  temp2 = b_std*b_std/b_len
+
+  return np.sqrt(temp1 + temp2)
+
+def stats_tvalue(a, b, axis, delta = 0):
+  a_mean = a.mean(axis=axis)
+  b_mean = b.mean(axis=axis)
+
+  return (a_mean - b_mean - delta) / stats_standard_error(a, b, axis)
+
+def stats_pvalue(a, b, axis, delta, left:bool = False):
+  """
+  Single-tailed 2-sample t-test.
+
+  Returns p-value for the null hypothesis: mean(a) - mean(b) >= delta.
+  :param a: numpy 2d array
+  :param b: numpy 2d array
+  :param axis: which axis to do the calculations across
+  :param delta: test value of mean differences
+  :param left: if true then use <= delta instead of >= delta
+  :return: p-value
+  """
+  # implement our own pvalue calculation because the built-in t-test (t,p values)
+  # only offer delta=0 , e.g. m1-m1 ? 0
+  # we are however interested in m1-m2 ? delta
+  t_value = stats_tvalue(a, b, axis, delta)
+
+  # 2-sample degrees of freedom is using the array sizes - 2.
+  dof = a.shape[axis] + b.shape[axis] - 2
+
+  if left:
+    # left tailed test. e.g. m1-m2 <= delta
+    return sc.t.cdf(t_value, dof)
+  else:
+    # right tailed test. e.g. m1-m2 >= delta
+    return sc.t.sf(t_value, dof)
+  # a left+right tailed test is a 2-tail t-test and can be done using ttest_ind for delta=0
+
+def print_comparable_analysis(comparable_metrics_iter, label_header, data_header, output_comparable: str, output_comparable_significant: str):
+  baseline_value = _BASELINE[1]
+  baseline_index = label_header.index(_BASELINE[0])
+
+  old_baseline_label_list = None
+  delta = _DELTA
+  filter_value = _IGNORE_PAIR[1]
+  filter_index = label_header.index(_IGNORE_PAIR[0])
+
+  pvalue_threshold = _PVALUE_THRESHOLD
+  ci_threshold = (1 - _PVALUE_THRESHOLD) * 100.0
+
+  with open(output_comparable, "w") as output_file:
+
+    csv_writer = csv.writer(output_file)
+    csv_writer.writerow(label_header + ['mean', 'mean_diff', 'sem', 'pvalue_2tailed', 'pvalue_gt%d' %(_DELTA), 'pvalue_gt%d' %(_DELTA2)])
+
+    print("------------------------------------------------------------------")
+    print("Comparison against the baseline %s = %s" %(_BASELINE, baseline_value))
+    print("--- Right-tailed t-test checks if the baseline >= current %s by at least %d" %(_BASELINE[0], delta))
+    print()
+
+    global_stats = {'better_than_delta': [], 'better_than_delta_p95': []}
+
+    for nested_it in comparable_metrics_iter:
+      print("************************")
+
+      better_than_delta = []
+      better_than_delta_p95 = []
+
+      saw_baseline_once = False
+
+      for ((baseline_label_list, baseline_np_data_2d), (rest_label_list, rest_np_data_2d)) in nested_it:
+        _debug_print("baseline_label_list:", baseline_label_list)
+        _debug_print("baseline_np_data_2d:", baseline_np_data_2d)
+        _debug_print("rest_label_list:", rest_label_list)
+        _debug_print("rest_np_data_2d:", rest_np_data_2d)
+
+        mean_diff = baseline_np_data_2d.mean(axis=0) - rest_np_data_2d.mean(axis=0)
+        # 2-sample 2-tailed t-test with delta=0
+        # e.g. "Is it true that usually the two sample means are different?"
+        t_statistic, t_pvalue = sc.ttest_ind(baseline_np_data_2d, rest_np_data_2d, axis=0)
+
+        # 2-sample 1-tailed t-test with delta=50
+        # e.g. "Is it true that usually the sample means better than 50ms?"
+        t2 = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta)
+        p2 = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta)
+
+        t2_b = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2)
+        p2_b = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2)
+
+        print("%s vs %s" %(rest_label_list, baseline_value))
+        print("                           ", data_header)
+        print("Mean Difference:           ", mean_diff)
+        print("T-test (2-tailed) != 0:      t=%s, p=%s" %(t_statistic, t_pvalue))
+        print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA, t2, p2))
+        print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA2, t2_b, p2_b))
+
+        def write_out_values(label_list, *args):
+          csv_writer.writerow(label_list + [i[_PLOT_DATA_INDEX] for i in args])
+
+        sem = stats_standard_error(baseline_np_data_2d, rest_np_data_2d, axis=0)
+        if saw_baseline_once == False:
+          saw_baseline_once = True
+          base_sem = stats_standard_error_one(baseline_np_data_2d, axis=0)
+          write_out_values(baseline_label_list, baseline_np_data_2d.mean(axis=0), [0], base_sem, [None], [None], [None])
+        write_out_values(rest_label_list, rest_np_data_2d.mean(axis=0), mean_diff, sem, t_pvalue, p2, p2_b)
+
+        # now do the global statistics aggregation
+
+        if rest_label_list[filter_index] == filter_value:
+          continue
+
+        if mean_diff > delta:
+          better_than_delta.append((mean_diff, p2, rest_label_list))
+
+          if p2 <= pvalue_threshold:
+            better_than_delta_p95.append((mean_diff, rest_label_list))
+
+      if better_than_delta:
+        global_stats['better_than_delta'].append(better_than_delta)
+      if better_than_delta_p95:
+        global_stats['better_than_delta_p95'].append(better_than_delta_p95)
+
+    print("------------------------")
+    print("Global statistics:")
+    print("//// Rows with %s=%s are ignored here." %_IGNORE_PAIR)
+    print("- # of results with mean diff better than delta(%d)       = %d" %(delta, len(global_stats['better_than_delta'])))
+    print("    > (meandiff, pvalue, labels)")
+    for i in global_stats['better_than_delta']:
+      print("    > %s" %i)
+    print("- # of results with mean diff better than delta(%d) CI%d%% = %d" %(delta, ci_threshold, len(global_stats['better_than_delta_p95'])))
+    print("    > (meandiff, labels)")
+    for i in global_stats['better_than_delta_p95']:
+      print("    > %s" %i)
+
+def main():
+  global _debug
+  global _DELTA
+  global _PVALUE_THRESHOLD
+
+  opts = parse_options()
+  _debug = opts.debug
+  _debug_print("parsed options: ", opts)
+
+  _PVALUE_THRESHOLD = opts.pvalue_threshold or _PVALUE_THRESHOLD
+
+  for file_name in opts.input_files:
+    with open(file_name, 'r') as input_file:
+      (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file)
+      print_analysis(grouped_numpy_iter, label_header, data_header, opts.output_samples)
+
+    with open(file_name, 'r') as input_file:
+      (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file)
+      without_baseline_iter = group_by_without_baseline_key(grouped_numpy_iter, label_header)
+      #_debug_print_gen(without_baseline_iter)
+
+      comparable_metrics_iter = iterate_comparable_metrics(without_baseline_iter, label_header)
+      print_comparable_analysis(comparable_metrics_iter, label_header, data_header, opts.output_comparable, opts.output_comparable_significant)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py
new file mode 100755
index 0000000..780bb4e
--- /dev/null
+++ b/startop/scripts/app_startup/app_startup_runner.py
@@ -0,0 +1,322 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+
+#
+#
+# Measure application start-up time by launching applications under various combinations.
+# See --help for more details.
+#
+#
+# Sample usage:
+# $> ./app_startup_runner.py -p com.google.android.calculator -r warm -r cold -lc 10  -o out.csv
+# $> ./analyze_metrics.py out.csv
+#
+#
+
+import argparse
+import csv
+import itertools
+import os
+import subprocess
+import sys
+import tempfile
+from typing import Any, Callable, Dict, Generic, Iterable, List, NamedTuple, TextIO, Tuple, TypeVar, Optional, Union
+
+# The following command line options participate in the combinatorial generation.
+# All other arguments have a global effect.
+_COMBINATORIAL_OPTIONS=['packages', 'readaheads', 'compiler_filters']
+_TRACING_READAHEADS=['mlock', 'fadvise']
+_FORWARD_OPTIONS={'loop_count': '--count'}
+_RUN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'run_app_with_prefetch')
+
+RunCommandArgs = NamedTuple('RunCommandArgs', [('package', str), ('readahead', str), ('compiler_filter', Optional[str])])
+CollectorPackageInfo = NamedTuple('CollectorPackageInfo', [('package', str), ('compiler_filter', str)])
+_COLLECTOR_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'collector')
+_COLLECTOR_TIMEOUT_MULTIPLIER = 2 # take the regular --timeout and multiply by 2; systrace starts up slowly.
+
+_UNLOCK_SCREEN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'unlock_screen')
+
+# This must be the only mutable global variable. All other global variables are constants to avoid magic literals.
+_debug = False  # See -d/--debug flag.
+_DEBUG_FORCE = None  # Ignore -d/--debug if this is not none.
+
+# Type hinting names.
+T = TypeVar('T')
+NamedTupleMeta = Callable[..., T]  # approximation of a (S : NamedTuple<T> where S() == T) metatype.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Run one or more Android applications under various settings in order to measure startup time.")
+  # argparse considers args starting with - and -- optional in --help, even though required=True.
+  # by using a named argument group --help will clearly say that it's required instead of optional.
+  required_named = parser.add_argument_group('required named arguments')
+  required_named.add_argument('-p', '--package', action='append', dest='packages', help='package of the application', required=True)
+  required_named.add_argument('-r', '--readahead', action='append', dest='readaheads', help='which readahead mode to use', choices=('warm', 'cold', 'mlock', 'fadvise'), required=True)
+
+  # optional arguments
+  # use a group here to get the required arguments to appear 'above' the optional arguments in help.
+  optional_named = parser.add_argument_group('optional named arguments')
+  optional_named.add_argument('-c', '--compiler-filter', action='append', dest='compiler_filters', help='which compiler filter to use. if omitted it does not enforce the app\'s compiler filter', choices=('speed', 'speed-profile', 'quicken'))
+  optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps')
+  optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+  optional_named.add_argument('-o', '--output', dest='output', action='store', help='Write CSV output to file.')
+  optional_named.add_argument('-t', '--timeout', dest='timeout', action='store', type=int, help='Timeout after this many seconds when executing a single run.')
+  optional_named.add_argument('-lc', '--loop-count', dest='loop_count', default=1, type=int, action='store', help='How many times to loop a single run.')
+  optional_named.add_argument('-in', '--inodes', dest='inodes', type=str, action='store', help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)')
+
+  return parser.parse_args(argv)
+
+# TODO: refactor this with a common library file with analyze_metrics.py
+def _debug_print(*args, **kwargs):
+  """Print the args to sys.stderr if the --debug/-d flag was passed in."""
+  if _debug:
+    print(*args, **kwargs, file=sys.stderr)
+
+def _expand_gen_repr(args):
+  """Like repr but any generator-like object has its iterator consumed
+  and then called repr on."""
+  new_args_list = []
+  for i in args:
+    # detect iterable objects that do not have their own override of __str__
+    if hasattr(i, '__iter__'):
+      to_str = getattr(i, '__str__')
+      if to_str.__objclass__ == object:
+        # the repr for a generator is just type+address, expand it out instead.
+        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
+        continue
+    # normal case: uses the built-in to-string
+    new_args_list.append(i)
+  return new_args_list
+
+def _debug_print_gen(*args, **kwargs):
+  """Like _debug_print but will turn any iterable args into a list."""
+  if not _debug:
+    return
+
+  new_args_list = _expand_gen_repr(args)
+  _debug_print(*new_args_list, **kwargs)
+
+def _debug_print_nd(*args, **kwargs):
+  """Like _debug_print but will turn any NamedTuple-type args into a string."""
+  if not _debug:
+    return
+
+  new_args_list = []
+  for i in args:
+    if hasattr(i, '_field_types'):
+      new_args_list.append("%s: %s" %(i.__name__, i._field_types))
+    else:
+      new_args_list.append(i)
+
+  _debug_print(*new_args_list, **kwargs)
+
+def dict_lookup_any_key(dictionary: dict, *keys: List[Any]):
+  for k in keys:
+    if k in dictionary:
+      return dictionary[k]
+  raise KeyError("None of the keys %s were in the dictionary" %(keys))
+
+def generate_run_combinations(named_tuple: NamedTupleMeta[T], opts_dict: Dict[str, List[Optional[str]]])\
+    -> Iterable[T]:
+  """
+  Create all possible combinations given the values in opts_dict[named_tuple._fields].
+
+  :type T: type annotation for the named_tuple type.
+  :param named_tuple: named tuple type, whose fields are used to make combinations for
+  :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields.
+  :return: an iterable over named_tuple instances.
+  """
+  combinations_list = []
+  for k in named_tuple._fields:
+    # the key can be either singular or plural , e.g. 'package' or 'packages'
+    val = dict_lookup_any_key(opts_dict, k, k + "s")
+
+    # treat {'x': None} key value pairs as if it was [None]
+    # otherwise itertools.product throws an exception about not being able to iterate None.
+    combinations_list.append(val or [None])
+
+  _debug_print("opts_dict: ", opts_dict)
+  _debug_print_nd("named_tuple: ", named_tuple)
+  _debug_print("combinations_list: ", combinations_list)
+
+  for combo in itertools.product(*combinations_list):
+    yield named_tuple(*combo)
+
+def key_to_cmdline_flag(key: str) -> str:
+  """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """
+  if key.endswith("s"):
+    key = key[:-1]
+  return "--" + key.replace("_", "-")
+
+def as_run_command(tpl: NamedTuple) -> List[Union[str, Any]]:
+  """
+  Convert a named tuple into a command-line compatible arguments list.
+
+  Example: ABC(1, 2, 3) -> ['--a', 1, '--b', 2, '--c', 3]
+  """
+  args = []
+  for key, value in tpl._asdict().items():
+    if value is None:
+      continue
+    args.append(key_to_cmdline_flag(key))
+    args.append(value)
+  return args
+
+def generate_group_run_combinations(run_combinations: Iterable[NamedTuple], dst_nt: NamedTupleMeta[T])\
+    -> Iterable[Tuple[T, Iterable[NamedTuple]]]:
+
+  def group_by_keys(src_nt):
+    src_d = src_nt._asdict()
+    # now remove the keys that aren't legal in dst.
+    for illegal_key in set(src_d.keys()) - set(dst_nt._fields):
+      if illegal_key in src_d:
+        del src_d[illegal_key]
+
+    return dst_nt(**src_d)
+
+  for args_list_it in itertools.groupby(run_combinations, group_by_keys):
+    (group_key_value, args_it) = args_list_it
+    yield (group_key_value, args_it)
+
+def parse_run_script_csv_file(csv_file: TextIO) -> List[int]:
+  """Parse a CSV file full of integers into a flat int list."""
+  csv_reader = csv.reader(csv_file)
+  arr = []
+  for row in csv_reader:
+    for i in row:
+      if i:
+        arr.append(int(i))
+  return arr
+
+def make_script_command_with_temp_output(script: str, args: List[str], **kwargs)\
+    -> Tuple[str, TextIO]:
+  """
+  Create a command to run a script given the args.
+  Appends --count <loop_count> --output <tmp-file-name>.
+  Returns a tuple (cmd, tmp_file)
+  """
+  tmp_output_file = tempfile.NamedTemporaryFile(mode='r')
+  cmd = [script] + args
+  for key, value in kwargs.items():
+    cmd += ['--%s' %(key), "%s" %(value)]
+  if _debug:
+    cmd += ['--verbose']
+  cmd = cmd + ["--output", tmp_output_file.name]
+  return cmd, tmp_output_file
+
+def execute_arbitrary_command(cmd: List[str], simulate: bool, timeout: int) -> Tuple[bool, str]:
+  if simulate:
+    print(" ".join(cmd))
+    return (True, "")
+  else:
+    _debug_print("[EXECUTE]", cmd)
+    proc = subprocess.Popen(cmd,
+                            stderr=subprocess.STDOUT,
+                            stdout=subprocess.PIPE,
+                            universal_newlines=True)
+    try:
+      script_output = proc.communicate(timeout=timeout)[0]
+    except subprocess.TimeoutExpired:
+      print("[TIMEDOUT]")
+      proc.kill()
+      script_output = proc.communicate()[0]
+
+    _debug_print("[STDOUT]", script_output)
+    return_code = proc.wait()
+    passed = (return_code == 0)
+    _debug_print("[$?]", return_code)
+    if not passed:
+      print("[FAILED, code:%s]" %(return_code), script_output, file=sys.stderr)
+
+    return (passed, script_output)
+
+def execute_run_combos(grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, inodes_path: str, timeout: int, loop_count: int, need_trace: bool):
+  # nothing will work if the screen isn't unlocked first.
+  execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT], simulate, timeout)
+
+  for collector_info, run_combos in grouped_run_combos:
+    #collector_args = ["--package", package_name]
+    collector_args = as_run_command(collector_info)
+    # TODO: forward --wait_time for how long systrace runs?
+    # TODO: forward --trace_buffer_size for size of systrace buffer size?
+    collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output(_COLLECTOR_SCRIPT, collector_args, inodes=inodes_path)
+
+    with collector_tmp_output_file:
+      collector_passed = True
+      if need_trace:
+        collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout
+        (collector_passed, collector_script_output) = execute_arbitrary_command(collector_cmd, simulate, collector_timeout)
+        # TODO: consider to print a ; collector wrote file to <...> into the CSV file so we know it was ran.
+
+      for combos in run_combos:
+        args = as_run_command(combos)
+
+        cmd, tmp_output_file = make_script_command_with_temp_output(_RUN_SCRIPT, args, count=loop_count, input=collector_tmp_output_file.name)
+        with tmp_output_file:
+          (passed, script_output) = execute_arbitrary_command(cmd, simulate, timeout)
+          parsed_output = simulate and [1,2,3] or parse_run_script_csv_file(tmp_output_file)
+          yield (passed, script_output, parsed_output)
+
+def gather_results(commands: Iterable[Tuple[bool, str, List[int]]], key_list: List[str], value_list: List[Tuple[str, ...]]):
+  _debug_print("gather_results: key_list = ", key_list)
+  yield key_list + ["time(ms)"]
+
+  stringify_none = lambda s: s is None and "<none>" or s
+
+  for ((passed, script_output, run_result_list), values) in itertools.zip_longest(commands, value_list):
+    if not passed:
+      continue
+    for result in run_result_list:
+      yield [stringify_none(i) for i in values] + [result]
+
+    yield ["; avg(%s), min(%s), max(%s), count(%s)" %(sum(run_result_list, 0.0) / len(run_result_list), min(run_result_list), max(run_result_list), len(run_result_list)) ]
+
+def eval_and_save_to_csv(output, annotated_result_values):
+  csv_writer = csv.writer(output)
+  for row in annotated_result_values:
+    csv_writer.writerow(row)
+    output.flush() # see the output live.
+
+def main():
+  global _debug
+
+  opts = parse_options()
+  _debug = opts.debug
+  if _DEBUG_FORCE is not None:
+    _debug = _DEBUG_FORCE
+  _debug_print("parsed options: ", opts)
+  need_trace = not not set(opts.readaheads).intersection(set(_TRACING_READAHEADS))
+  if need_trace and not opts.inodes:
+    print("Error: Missing -in/--inodes, required when using a readahead of %s" %(_TRACING_READAHEADS), file=sys.stderr)
+    return 1
+
+  output_file = opts.output and open(opts.output, 'w') or sys.stdout
+
+  combos = lambda: generate_run_combinations(RunCommandArgs, vars(opts))
+  _debug_print_gen("run combinations: ", combos())
+
+  grouped_combos = lambda: generate_group_run_combinations(combos(), CollectorPackageInfo)
+  _debug_print_gen("grouped run combinations: ", grouped_combos())
+
+  exec = execute_run_combos(grouped_combos(), opts.simulate, opts.inodes, opts.timeout, opts.loop_count, need_trace)
+  results = gather_results(exec, _COMBINATORIAL_OPTIONS, combos())
+  eval_and_save_to_csv(output_file, results)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py
new file mode 100755
index 0000000..f96f802a
--- /dev/null
+++ b/startop/scripts/app_startup/app_startup_runner_test.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+#
+
+"""
+Unit tests for the app_startup_runner.py script.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> ./app_startup_runner_test.py
+  $> pytest app_startup_runner_test.py
+  $> python -m pytest app_startup_runner_test.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+
+# global imports
+from contextlib import contextmanager
+import io
+import shlex
+import sys
+import typing
+
+# pip imports
+import pytest
+
+# local imports
+import app_startup_runner as asr
+
+#
+# Argument Parsing Helpers
+#
+
+@contextmanager
+def ignore_stdout_stderr():
+  """Ignore stdout/stderr output for duration of this context."""
+  old_stdout = sys.stdout
+  old_stderr = sys.stderr
+  sys.stdout = io.StringIO()
+  sys.stderr = io.StringIO()
+  try:
+    yield
+  finally:
+    sys.stdout = old_stdout
+    sys.stderr = old_stderr
+
+@contextmanager
+def argparse_bad_argument(msg):
+  """
+  Assert that a SystemExit is raised when executing this context.
+  If the assertion fails, print the message 'msg'.
+  """
+  with pytest.raises(SystemExit, message=msg):
+    with ignore_stdout_stderr():
+      yield
+
+def assert_bad_argument(args, msg):
+  """
+  Assert that the command line arguments in 'args' are malformed.
+  Prints 'msg' if the assertion fails.
+  """
+  with argparse_bad_argument(msg):
+    parse_args(args)
+
+def parse_args(args):
+  """
+  :param args: command-line like arguments as a single string
+  :return:  dictionary of parsed key/values
+  """
+  # "-a b -c d"    => ['-a', 'b', '-c', 'd']
+  return vars(asr.parse_options(shlex.split(args)))
+
+def default_dict_for_parsed_args(**kwargs):
+  """
+  # Combine it with all of the "optional" parameters' default values.
+  """
+  d = {'compiler_filters': None, 'simulate': False, 'debug': False, 'output': None, 'timeout': None, 'loop_count': 1, 'inodes': None}
+  d.update(kwargs)
+  return d
+
+def default_mock_dict_for_parsed_args(include_optional=True, **kwargs):
+  """
+  Combine default dict with all optional parameters with some mock required parameters.
+  """
+  d = {'packages': ['com.fake.package'], 'readaheads': ['warm']}
+  if include_optional:
+    d.update(default_dict_for_parsed_args())
+  d.update(kwargs)
+  return d
+
+def parse_optional_args(str):
+  """
+  Parse an argument string which already includes all the required arguments
+  in default_mock_dict_for_parsed_args.
+  """
+  req = "--package com.fake.package --readahead warm"
+  return parse_args("%s %s" %(req, str))
+
+def test_argparse():
+  # missing arguments
+  assert_bad_argument("", "-p and -r are required")
+  assert_bad_argument("-r warm", "-p is required")
+  assert_bad_argument("--readahead warm", "-p is required")
+  assert_bad_argument("-p com.fake.package", "-r is required")
+  assert_bad_argument("--package com.fake.package", "-r is required")
+
+  # required arguments are parsed correctly
+  ad = default_dict_for_parsed_args  # assert dict
+
+  assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], readaheads=['warm'])
+  assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], readaheads=['warm'])
+
+  assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
+  assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
+
+  # optional arguments are parsed correctly.
+  mad = default_mock_dict_for_parsed_args  # mock assert dict
+  assert parse_optional_args("--output filename.csv") == mad(output='filename.csv')
+  assert parse_optional_args("-o filename.csv") == mad(output='filename.csv')
+
+  assert parse_optional_args("--timeout 123") == mad(timeout=123)
+  assert parse_optional_args("-t 456") == mad(timeout=456)
+
+  assert parse_optional_args("--loop-count 123") == mad(loop_count=123)
+  assert parse_optional_args("-lc 456") == mad(loop_count=456)
+
+  assert parse_optional_args("--inodes bar") == mad(inodes="bar")
+  assert parse_optional_args("-in baz") == mad(inodes="baz")
+
+
+def generate_run_combinations(*args):
+  # expand out the generator values so that assert x == y works properly.
+  return [i for i in asr.generate_run_combinations(*args)]
+
+def test_generate_run_combinations():
+  blank_nd = typing.NamedTuple('Blank')
+  assert generate_run_combinations(blank_nd, {}) == [()], "empty"
+  assert generate_run_combinations(blank_nd, {'a' : ['a1', 'a2']}) == [()], "empty filter"
+  a_nd = typing.NamedTuple('A', [('a', str)])
+  assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None"
+  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), ('a2',)], "one item"
+  assert generate_run_combinations(a_nd,
+                                   {'a' : ['a1', 'a2'], 'b': ['b1', 'b2']}) == [('a1',), ('a2',)],\
+      "one item filter"
+  ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)])
+  assert generate_run_combinations(ab_nd,
+                                   {'a': ['a1', 'a2'],
+                                    'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                            ab_nd('a1', 'b2'),
+                                                            ab_nd('a2', 'b1'),
+                                                            ab_nd('a2', 'b2')],\
+      "two items"
+
+  assert generate_run_combinations(ab_nd,
+                                   {'as': ['a1', 'a2'],
+                                    'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                             ab_nd('a1', 'b2'),
+                                                             ab_nd('a2', 'b1'),
+                                                             ab_nd('a2', 'b2')],\
+      "two items plural"
+
+def test_key_to_cmdline_flag():
+  assert asr.key_to_cmdline_flag("abc") == "--abc"
+  assert asr.key_to_cmdline_flag("foos") == "--foo"
+  assert asr.key_to_cmdline_flag("ba_r") == "--ba-r"
+  assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z"
+
+
+def test_make_script_command_with_temp_output():
+  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=[], count=1)
+  with tmp_file:
+    assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name]
+
+  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=['a', 'b'], count=2)
+  with tmp_file:
+    assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", tmp_file.name]
+
+def test_parse_run_script_csv_file():
+  # empty file -> empty list
+  f = io.StringIO("")
+  assert asr.parse_run_script_csv_file(f) == []
+
+  # common case
+  f = io.StringIO("1,2,3")
+  assert asr.parse_run_script_csv_file(f) == [1,2,3]
+
+  # ignore trailing comma
+  f = io.StringIO("1,2,3,4,5,")
+  assert asr.parse_run_script_csv_file(f) == [1,2,3,4,5]
+
+
+if __name__ == '__main__':
+  pytest.main()
diff --git a/startop/scripts/app_startup/force_compiler_filter b/startop/scripts/app_startup/force_compiler_filter
new file mode 100755
index 0000000..78e915b
--- /dev/null
+++ b/startop/scripts/app_startup/force_compiler_filter
@@ -0,0 +1,173 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+#
+# Forces an application APK to be compiled (by ART's dex2oat)
+# with a specific compiler filter.
+#
+# Example usage:
+#    $> ./force_compiler_filter -p com.google.android.apps.maps -c speed-profile
+#
+# (The application may be started/stopped as a side effect)
+#
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+usage() {
+    cat <<EOF
+Usage: $(basename $0) [OPTION]...
+
+  Required:
+    -p, --package               package of the app to recompile
+    -c, --compiler-filter       override the compiler filter if set (default none)
+                                valid options are listed by: adb shell cmd package, under compile -m
+
+  Optional:
+    -a, --activity              activity of the app to recompile
+    -h, --help                  usage information (this)
+    -v, --verbose               enable extra verbose printing
+    -w, --wait_time             how long to wait for app startup (default 10) in seconds
+EOF
+}
+
+wait_time="10" # seconds
+
+parse_arguments() {
+  while [[ $# -gt 0 ]]; do
+    case "$1" in
+      -a|--activity)
+        activity="$2"
+        shift
+        ;;
+      -h|--help)
+        usage
+        exit 0
+        ;;
+      -p|--package)
+        package="$2"
+        shift
+        ;;
+      -w|--wait_time)
+        wait_time="$2"
+        shift
+        ;;
+      -c|--compiler-filter)
+        compiler_filter="$2"
+        shift
+        ;;
+      -v|--verbose)
+        verbose="y"
+        ;;
+    esac
+    shift
+  done
+
+  if [[ -z "$compiler_filter" ]]; then
+    echo "Missing required --compiler-filter" >&2
+    echo ""
+    usage
+    exit 1
+  fi
+  if [[ -z "$package" ]]; then
+    echo "Missing required --package" >&2
+    echo ""
+    usage
+    exit 1
+  fi
+
+  if [[ "$activity" == "" ]]; then
+    activity="$(get_activity_name "$package")"
+    if [[ "$activity" == "" ]]; then
+      echo "Activity name could not be found, invalid package name?" 1>&2
+      exit 1
+    else
+      verbose_print "Activity name inferred: " "$activity"
+    fi
+  fi
+}
+
+get_activity_name() {
+  local package="$1"
+  local action_key="android.intent.action.MAIN:"
+
+  local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
+  verbose_print $activity_line
+  IFS="/" read -a array <<< "$activity_line"
+  local activity_name="${array[1]}"
+  echo "$activity_name"
+  #adb shell am start "$package/$activity_name"
+}
+
+remote_pidof() {
+  local procname="$1"
+  adb shell ps | grep "$procname" | awk '{print $2;}'
+}
+
+remote_pkill() {
+  local procname="$1"
+  shift
+
+  local the_pids=$(remote_pidof "$procname")
+  local pid
+
+  for pid in $the_pids; do
+    verbose_print adb shell kill "$@" "$pid"
+    adb shell kill "$@" "$pid"
+  done
+}
+
+force_package_compilation() {
+  local arg_compiler_filter="$1"
+  local arg_package="$2"
+
+  if [[ $arg_compiler_filter == speed-profile ]]; then
+    # Force the running app to dump its profiles to disk.
+    remote_pkill "$arg_package" -SIGUSR1
+    sleep 1 # give some time for above to complete.
+  fi
+
+  adb shell cmd package compile -m "$arg_compiler_filter" -f "$arg_package"
+}
+
+main() {
+  parse_arguments "$@"
+
+  if [[ $compiler_filter == speed-profile ]]; then
+    # screen needs to be unlocked in order to run an app
+    "$DIR"/unlock_screen
+
+    am_output="$(adb shell am start -S -W "$package"/"$activity")"
+    if [[ $? -ne 0 ]]; then
+      echo "am start failed" >&2
+      exit 1
+    fi
+
+    verbose_print "$am_output"
+    # give some time for app startup to complete.
+    # this is supposed to be an upper bound for measuring startup time.
+    sleep "$wait_time"
+  fi
+
+  force_package_compilation "$compiler_filter" "$package"
+
+  # kill the application to ensure next time it's started,
+  # it picks up the correct compilation filter.
+  adb shell am force-stop "$package"
+  remote_pkill "$package"
+}
+
+main "$@"
diff --git a/startop/scripts/app_startup/launch_application b/startop/scripts/app_startup/launch_application
new file mode 100755
index 0000000..bc4ec51
--- /dev/null
+++ b/startop/scripts/app_startup/launch_application
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+launch_application() {
+  local package="$1"
+  local activity="$2"
+  local am_output="$(adb shell am start -S -W "$package"/"$activity")"
+  verbose_print adb shell am start -S -W "$package"/"$activity"
+  if [[ $? -ne 0 ]]; then
+    echo "am start failed" >&2
+
+    return 1
+  fi
+
+  # for everything else use the am start "TotalTime" output.
+  verbose_print "$am_output"
+  local total_time="$(echo "$am_output" | grep 'TotalTime:' | sed 's/TotalTime: //g')"
+  verbose_print "total time: $total_time"
+
+  # TODO: Extract alternative metrics such as the #reportFullyDrawn.
+
+  echo "$total_time"
+}
+
+launch_application "$@"
diff --git a/startop/scripts/app_startup/lib/common b/startop/scripts/app_startup/lib/common
new file mode 100755
index 0000000..4d5a53e
--- /dev/null
+++ b/startop/scripts/app_startup/lib/common
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [[ -z $ANDROID_BUILD_TOP ]]; then
+  echo "Please run source build/envsetup.sh first" >&2
+  exit 1
+fi
+
+source $ANDROID_BUILD_TOP/build/envsetup.sh
+
+verbose_print() {
+  if [[ "$verbose" == "y" ]]; then
+    echo "$@" >&2
+  fi
+}
diff --git a/startop/scripts/app_startup/query_compiler_filter.py b/startop/scripts/app_startup/query_compiler_filter.py
new file mode 100755
index 0000000..dc97c66
--- /dev/null
+++ b/startop/scripts/app_startup/query_compiler_filter.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+
+#
+#
+# Query the current compiler filter for an application by its package name.
+# (By parsing the results of the 'adb shell dumpsys package $package' command).
+# The output is a string "$compilation_filter $compilation_reason $isa".
+#
+# See --help for more details.
+#
+# -----------------------------------
+#
+# Sample usage:
+#
+# $> ./query_compiler_filter.py --package com.google.android.calculator
+# speed-profile unknown arm64
+#
+
+import argparse
+import sys
+import re
+
+# TODO: refactor this with a common library file with analyze_metrics.py
+import app_startup_runner
+from app_startup_runner import _debug_print
+from app_startup_runner import execute_arbitrary_command
+
+from typing import List, NamedTuple, Iterable
+
+_DEBUG_FORCE = None  # Ignore -d/--debug if this is not none.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Query the compiler filter for a package.")
+  # argparse considers args starting with - and -- optional in --help, even though required=True.
+  # by using a named argument group --help will clearly say that it's required instead of optional.
+  required_named = parser.add_argument_group('required named arguments')
+  required_named.add_argument('-p', '--package', action='store', dest='package', help='package of the application', required=True)
+
+  # optional arguments
+  # use a group here to get the required arguments to appear 'above' the optional arguments in help.
+  optional_named = parser.add_argument_group('optional named arguments')
+  optional_named.add_argument('-i', '--isa', '--instruction-set', action='store', dest='instruction_set', help='which instruction set to select. defaults to the first one available if not specified.', choices=('arm64', 'arm', 'x86_64', 'x86'))
+  optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps')
+  optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+
+  return parser.parse_args(argv)
+
+def remote_dumpsys_package(package: str, simulate: bool) -> str:
+  # --simulate is used for interactive debugging/development, but also for the unit test.
+  if simulate:
+    return """
+Dexopt state:
+  [%s]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      arm64: [status=speed-profile] [reason=unknown]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      arm: [status=speed] [reason=first-boot]
+    path: /data/app/%s-D7s8PLidqqEq7Jc7UH_a5A==/base.apk
+      x86: [status=quicken] [reason=install]
+""" %(package, package, package, package)
+
+  code, res = execute_arbitrary_command(['adb', 'shell', 'dumpsys', 'package', package], simulate=False, timeout=5)
+  if code:
+    return res
+  else:
+    raise AssertionError("Failed to dumpsys package, errors = %s", res)
+
+ParseTree = NamedTuple('ParseTree', [('label', str), ('children', List['ParseTree'])])
+DexoptState = ParseTree # With the Dexopt state: label
+ParseResult = NamedTuple('ParseResult', [('remainder', List[str]), ('tree', ParseTree)])
+
+def find_parse_subtree(parse_tree: ParseTree, match_regex: str) -> ParseTree:
+  if re.match(match_regex, parse_tree.label):
+    return parse_tree
+
+  for node in parse_tree.children:
+    res = find_parse_subtree(node, match_regex)
+    if res:
+      return res
+
+  return None
+
+def find_parse_children(parse_tree: ParseTree, match_regex: str) -> Iterable[ParseTree]:
+  for node in parse_tree.children:
+    if re.match(match_regex, node.label):
+      yield node
+
+def parse_tab_subtree(label: str, str_lines: List[str], separator=' ', indent=-1) -> ParseResult:
+  children = []
+
+  get_indent_level = lambda line: len(line) - len(line.lstrip())
+
+  line_num = 0
+
+  keep_going = True
+  while keep_going:
+    keep_going = False
+
+    for line_num in range(len(str_lines)):
+      line = str_lines[line_num]
+      current_indent = get_indent_level(line)
+
+      _debug_print("INDENT=%d, LINE=%s" %(current_indent, line))
+
+      current_label = line.lstrip()
+
+      # skip empty lines
+      if line.lstrip() == "":
+        continue
+
+      if current_indent > indent:
+        parse_result = parse_tab_subtree(current_label, str_lines[line_num+1::], separator, current_indent)
+        str_lines = parse_result.remainder
+        children.append(parse_result.tree)
+        keep_going = True
+      else:
+        # current_indent <= indent
+        keep_going = False
+
+      break
+
+  new_remainder = str_lines[line_num::]
+  _debug_print("NEW REMAINDER: ", new_remainder)
+
+  parse_tree = ParseTree(label, children)
+  return ParseResult(new_remainder, parse_tree)
+
+def parse_tab_tree(str_tree: str, separator=' ', indentation_level=-1) -> ParseTree:
+
+  label = None
+  lst = []
+
+  line_num = 0
+  line_lst = str_tree.split("\n")
+
+  return parse_tab_subtree("", line_lst, separator, indentation_level).tree
+
+def parse_dexopt_state(dumpsys_tree: ParseTree) -> DexoptState:
+  res = find_parse_subtree(dumpsys_tree, "Dexopt(\s+)state[:]?")
+  if not res:
+    raise AssertionError("Could not find the Dexopt state")
+  return res
+
+def find_first_compiler_filter(dexopt_state: DexoptState, package: str, instruction_set: str) -> str:
+  lst = find_all_compiler_filters(dexopt_state, package)
+
+  _debug_print("all compiler filters: ", lst)
+
+  for compiler_filter_info in lst:
+    if not instruction_set:
+      return compiler_filter_info
+
+    if compiler_filter_info.isa == instruction_set:
+      return compiler_filter_info
+
+  return None
+
+CompilerFilterInfo = NamedTuple('CompilerFilterInfo', [('isa', str), ('status', str), ('reason', str)])
+
+def find_all_compiler_filters(dexopt_state: DexoptState, package: str) -> List[CompilerFilterInfo]:
+
+  lst = []
+  package_tree = find_parse_subtree(dexopt_state, re.escape("[%s]" %package))
+
+  if not package_tree:
+    raise AssertionError("Could not find any package subtree for package %s" %(package))
+
+  _debug_print("package tree: ", package_tree)
+
+  for path_tree in find_parse_children(package_tree, "path: "):
+    _debug_print("path tree: ", path_tree)
+
+    matchre = re.compile("([^:]+):\s+\[status=([^\]]+)\]\s+\[reason=([^\]]+)\]")
+
+    for isa_node in find_parse_children(path_tree, matchre):
+
+      matches = re.match(matchre, isa_node.label).groups()
+
+      info = CompilerFilterInfo(*matches)
+      lst.append(info)
+
+  return lst
+
+def main() -> int:
+  opts = parse_options()
+  app_startup_runner._debug = opts.debug
+  if _DEBUG_FORCE is not None:
+    app_startup_runner._debug = _DEBUG_FORCE
+  _debug_print("parsed options: ", opts)
+
+  # Note: This can often 'fail' if the package isn't actually installed.
+  package_dumpsys = remote_dumpsys_package(opts.package, opts.simulate)
+  _debug_print("package dumpsys: ", package_dumpsys)
+  dumpsys_parse_tree = parse_tab_tree(package_dumpsys, package_dumpsys)
+  _debug_print("parse tree: ", dumpsys_parse_tree)
+  dexopt_state = parse_dexopt_state(dumpsys_parse_tree)
+
+  filter = find_first_compiler_filter(dexopt_state, opts.package, opts.instruction_set)
+
+  if filter:
+    print(filter.status, end=' ')
+    print(filter.reason, end=' ')
+    print(filter.isa)
+  else:
+    print("ERROR: Could not find any compiler-filter for package %s, isa %s" %(opts.package, opts.instruction_set), file=sys.stderr)
+    return 1
+
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/query_compiler_filter_test.py b/startop/scripts/app_startup/query_compiler_filter_test.py
new file mode 100755
index 0000000..a751a43
--- /dev/null
+++ b/startop/scripts/app_startup/query_compiler_filter_test.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+#
+
+"""
+Unit tests for the query_compiler_filter.py script.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> ./query_compiler_filter.py
+  $> pytest query_compiler_filter.py
+  $> python -m pytest query_compiler_filter.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+
+# global imports
+from contextlib import contextmanager
+import io
+import shlex
+import sys
+import typing
+
+# pip imports
+import pytest
+
+# local imports
+import query_compiler_filter as qcf
+
+@contextmanager
+def redirect_stdout_stderr():
+  """Redirect stdout/stderr to a new StringIO for duration of context."""
+  old_stdout = sys.stdout
+  old_stderr = sys.stderr
+  new_stdout = io.StringIO()
+  sys.stdout = new_stdout
+  new_stderr = io.StringIO()
+  sys.stderr = new_stderr
+  try:
+    yield (new_stdout, new_stderr)
+  finally:
+    sys.stdout = old_stdout
+    sys.stderr = old_stderr
+    # Seek back to the beginning so we can read whatever was written into it.
+    new_stdout.seek(0)
+    new_stderr.seek(0)
+
+@contextmanager
+def replace_argv(argv):
+  """ Temporarily replace argv for duration of this context."""
+  old_argv = sys.argv
+  sys.argv = [sys.argv[0]] + argv
+  try:
+    yield
+  finally:
+    sys.argv = old_argv
+
+def exec_main(argv):
+  """Run the query_compiler_filter main function with the provided arguments.
+
+  Returns the stdout result when successful, assertion failure otherwise.
+  """
+  try:
+    with redirect_stdout_stderr() as (the_stdout, the_stderr):
+      with replace_argv(argv):
+        code = qcf.main()
+    assert 0 == code, the_stderr.readlines()
+
+    all_lines = the_stdout.readlines()
+    return "".join(all_lines)
+  finally:
+    the_stdout.close()
+    the_stderr.close()
+
+def test_query_compiler_filter():
+  # no --instruction-set specified: provide whatever was the 'first' filter.
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps']) == \
+      "speed-profile unknown arm64\n"
+
+  # specifying an instruction set finds the exact compiler filter match.
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'arm64']) == \
+      "speed-profile unknown arm64\n"
+
+  assert exec_main(['--simulate',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'arm']) == \
+      "speed first-boot arm\n"
+
+  assert exec_main(['--simulate',
+                    '--debug',
+                    '--package', 'com.google.android.apps.maps',
+                    '--instruction-set', 'x86']) == \
+      "quicken install x86\n"
+
+if __name__ == '__main__':
+  pytest.main()
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
new file mode 100755
index 0000000..ce63ff9
--- /dev/null
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -0,0 +1,381 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+usage() {
+    cat <<EOF
+Usage: run_app_with_prefetch --package <name> [OPTIONS]...
+
+    -p, --package <name>        package of the app to test
+    -a, --activity <name>       activity to use
+    -h, --help                  usage information (this)
+    -v, --verbose               enable extra verbose printing
+    -i, --input <file>          trace file protobuf (default 'TraceFile.pb')
+    -r, --readahead <mode>      cold, warm, fadvise, mlock (default 'warm')
+    -w, --when <when>           aot or jit (default 'aot')
+    -c, --count <count>         how many times to run (default 1)
+    -s, --sleep <sec>           how long to sleep after readahead
+    -t, --timeout <sec>         how many seconds to timeout in between each app run (default 10)
+    -o, --output <file.csv>     what file to write the performance results into as csv (default stdout)
+EOF
+}
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+needs_trace_file="n"
+input_file=""
+package=""
+mode='warm'
+count=2
+sleep_time=2
+timeout=10
+output="" # stdout by default
+when="aot"
+parse_arguments() {
+  while [[ $# -gt 0 ]]; do
+    case "$1" in
+      -h|--help)
+        usage
+        exit 0
+        ;;
+      -p|--package)
+        package="$2"
+        shift
+        ;;
+      -a|--activity)
+        activity="$2"
+        shift
+        ;;
+      -i|--input)
+        input_file="$2"
+        shift
+        ;;
+      -v|--verbose)
+        export verbose="y"
+        ;;
+      -r|--readahead)
+        mode="$2"
+        shift
+        ;;
+      -c|--count)
+        count="$2"
+        ((count+=1))
+        shift
+        ;;
+      -s|--sleep)
+        sleep_time="$2"
+        shift
+        ;;
+      -t|--timeout)
+        timeout="$2"
+        shift
+        ;;
+      -o|--output)
+        output="$2"
+        shift
+        ;;
+      -w|--when)
+        when="$2"
+        shift
+        ;;
+      --compiler-filter)
+        compiler_filter="$2"
+        shift
+        ;;
+      *)
+        echo "Invalid argument: $1" >&2
+        exit 1
+    esac
+    shift
+  done
+}
+
+echo_to_output_file() {
+  if [[ "x$output" != x ]]; then
+    echo "$@" >> $output
+  fi
+  # Always echo to stdout as well.
+  echo "$@"
+}
+
+get_activity_name() {
+  local package="$1"
+  local action_key="android.intent.action.MAIN:"
+
+  local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
+  #echo $activity_line
+  IFS="/" read -a array <<< "$activity_line"
+  local activity_name="${array[1]}"
+  echo "$activity_name"
+  #adb shell am start "$package/$activity_name"
+}
+
+find_package_path() {
+  local pkg="$1"
+
+  res="$(adb shell find "/data/app/$pkg"-'*' -maxdepth 0 2> /dev/null)"
+  if [[ -z $res ]]; then
+    res="$(adb shell find "/system/app/$pkg"-'*' -maxdepth 0 2> /dev/null)"
+  fi
+  echo "$res"
+}
+
+remote_pkill() {
+  local what="$1"
+  adb shell "for i in $(pid $what); do kill \$i; done"
+}
+
+# Main entry point
+if [[ $# -eq 0 ]]; then
+  usage
+  exit 1
+else
+  parse_arguments "$@"
+
+  # if we do not have have package exit early with an error
+  [[ "$package" == "" ]] && echo "--package not specified" 1>&2 && exit 1
+
+  if [[ $mode != "cold" && $mode != "warm" ]]; then
+    needs_trace_file="y"
+    if [[ -z "$input_file" ]] || ! [[ -f $input_file ]]; then
+      echo "--input not specified" 1>&2
+      exit 1
+    fi
+  fi
+
+  if [[ "$activity" == "" ]]; then
+    activity="$(get_activity_name "$package")"
+    if [[ "$activity" == "" ]]; then
+      echo "Activity name could not be found, invalid package name?" 1>&2
+      exit 1
+    else
+      verbose_print "Activity name inferred: " "$activity"
+    fi
+  fi
+fi
+
+adb root > /dev/null
+
+if [[ ($when == jit) || ($when == aot) ]] && [[ "$(adb shell getenforce)" != "Permissive" ]]; then
+  echo "Disable selinux permissions and restart framework."
+  adb shell setenforce 0
+  adb shell stop
+  adb shell start
+  adb wait-for-device
+fi
+
+# TODO: set performance governor etc, preferrably only once
+# before every single app run.
+
+# Kill everything before running.
+remote_pkill "$package"
+sleep 1
+
+timings_array=()
+
+package_path="$(find_package_path "$package")"
+if [[ $? -ne 0 ]]; then
+  echo "Failed to detect package path for '$package'" >&2
+  exit 1
+fi
+verbose_print "Package was in path '$package_path'"
+
+keep_application_trace_file=n
+application_trace_file_path="$package_path/TraceFile.pb"
+trace_file_directory="$package_path"
+if [[ $needs_trace_file == y ]]; then
+  # system server always passes down the package path in a hardcoded spot.
+  if [[ $when == "jit" ]]; then
+    verbose_print adb push "$input_file" "$application_trace_file_path"
+    adb push "$input_file" "$application_trace_file_path"
+    keep_application_trace_file="y"
+  else
+    # otherwise use a temporary directory to get normal non-jit behavior.
+    trace_file_directory="/data/local/tmp/prefetch/$package"
+    adb shell mkdir -p "$trace_file_directory"
+    verbose_print  adb push "$input_file" "$trace_file_directory/TraceFile.pb"
+    adb push "$input_file" "$trace_file_directory/TraceFile.pb"
+  fi
+fi
+
+# Everything other than JIT: remove the trace file,
+# otherwise system server activity hints will kick in
+# and the new just-in-time app pre-warmup will happen.
+if [[ $keep_application_trace_file == "n" ]]; then
+  adb shell "[[ -f '$application_trace_file_path' ]] && rm '$application_trace_file_path'"
+fi
+
+# Perform AOT readahead/pinning/etc when an application is about to be launched.
+# For JIT readahead, we allow the system to handle it itself (this is a no-op).
+#
+# For warm, cold, etc modes which don't need readahead this is always a no-op.
+perform_aot() {
+  local the_when="$1" # user: aot, jit
+  local the_mode="$2" # warm, cold, fadvise, mlock, etc.
+
+  if [[ $the_when != "aot" ]]; then
+    # TODO: just in time implementation.. should probably use system server.
+    return 0
+  fi
+
+  # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script.
+  if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then
+
+    # TODO: add activity_hint_sender.exp
+    verbose_print "starting with package=$package package_path=$trace_file_directory"
+    coproc hint_sender_fd { $ANDROID_BUILD_TOP/system/iorap/src/sh/activity_hint_sender.exp "$package" "$trace_file_directory" "$the_mode"; }
+    hint_sender_pid=$!
+    verbose_print "Activity hint sender began"
+
+    notification_success="n"
+    while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do
+      verbose_print "$hint_sender_output"
+      if [[ "$hint_sender_output" == "Press any key to send completed event..."* ]]; then
+        verbose_print "WE DID SEE NOTIFICATION SUCCESS."
+        notification_success='y'
+        # Give it some time to actually perform the readaheads.
+        sleep $sleep_time
+        break
+      fi
+    done
+
+    if [[ $notification_success == 'n' ]]; then
+      echo "[FATAL] Activity hint notification failed." 1>&2
+      exit 1
+    fi
+  fi
+}
+
+perform_aot_cleanup() {
+  local the_when="$1" # user: aot, jit
+  local the_mode="$2" # warm, cold, fadvise, mlock, etc.
+
+  if [[ $the_when != "aot" ]]; then
+    # TODO: just in time implementation.. should probably use system server.
+    return 0
+  fi
+
+  # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script.
+  if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then
+    # Clean up the hint sender by telling it that the launch was completed,
+    # and to shutdown the watcher.
+    echo "Done\n" >&"${hint_sender_fd[1]}"
+
+    while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do
+      verbose_print "$hint_sender_output"
+    done
+
+    wait $hint_sender_pid
+  fi
+}
+
+configure_compiler_filter() {
+  local the_compiler_filter="$1"
+  local the_package="$2"
+  local the_activity="$3"
+
+  if [[ -z $the_compiler_filter ]]; then
+    verbose_print "No --compiler-filter specified, don't need to force it."
+    return 0
+  fi
+
+  local current_compiler_filter_info="$("$DIR"/query_compiler_filter.py --package "$the_package")"
+  local res=$?
+  if [[ $res -ne 0 ]]; then
+    return $res
+  fi
+
+  local current_compiler_filter
+  local current_reason
+  local current_isa
+  read current_compiler_filter current_reason current_isa <<< "$current_compiler_filter_info"
+
+  verbose_print "Compiler Filter="$current_compiler_filter "Reason="$current_reason "Isa="$current_isa
+
+  # Don't trust reasons that aren't 'unknown' because that means we didn't manually force the compilation filter.
+  # (e.g. if any automatic system-triggered compilations are not unknown).
+  if [[ $current_reason != "unknown" ]] || [[ $current_compiler_filter != $the_compiler_filter ]]; then
+    verbose_print "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity"
+    "$DIR"/force_compiler_filter --compiler-filter "$the_compiler_filter" --package "$the_package" --activity "$the_activity"
+    res=$?
+  else
+    verbose_print "Queried compiler-filter matched requested compiler-filter, skip forcing."
+    res=0
+  fi
+
+  return $res
+}
+
+# Ensure the APK is currently compiled with whatever we passed in via --compiler-filter.
+# No-op if this option was not passed in.
+configure_compiler_filter "$compiler_filter" "$package" "$activity" || exit 1
+
+# TODO: This loop logic could probably be moved into app_startup_runner.py
+for ((i=0;i<count;++i)) do
+  verbose_print "=========================================="
+  verbose_print "====         ITERATION $i             ===="
+  verbose_print "=========================================="
+  if [[ $mode != "warm" ]]; then
+    verbose_print "Drop caches for non-warm start."
+    # Drop all caches to get cold starts.
+    adb shell "echo 3 > /proc/sys/vm/drop_caches"
+  fi
+
+  perform_aot "$when" "$mode"
+
+  verbose_print "Running with timeout $timeout"
+
+  # TODO: multiple metrics output.
+  total_time="$(timeout $timeout $DIR/launch_application "$package" "$activity")"
+
+  if [[ $? -ne 0 ]]; then
+    echo "WARNING: Skip bad result, try iteration again." >&2
+    ((i=i-1))
+    continue
+  fi
+
+  perform_aot_cleanup "$when" "$mode"
+
+  echo "Iteration $i. Total time was: $total_time"
+
+  timings_array+=($total_time)
+done
+
+# drop the first result which is usually garbage.
+timings_array=("${timings_array[@]:1}")
+
+
+# Print out interactive/debugging timings and averages.
+# Other scripts should use the --output flag and parse the CSV.
+for tim in "${timings_array[@]}"; do
+  echo_to_output_file -ne "$tim,"
+done
+echo_to_output_file ""
+
+average_string=$(echo "${timings_array[@]}" | awk '{s+=$0}END{print "Average:",s/NR}' RS=" ")
+echo -ne ${average_string}.
+if [[ x$output != x ]]; then
+  echo " Saved results to '$output'"
+fi
+
+# Temporary hack around multiple activities being launched with different package paths (for same app):
+# Clean up all left-over TraceFile.pb
+adb shell 'for i in $(find /data/app -name TraceFile.pb); do rm \$i; done'
+
+# Kill the process to ensure AM isn't keeping it around.
+remote_pkill "$package"
+
+exit 0
diff --git a/startop/scripts/app_startup/unlock_screen b/startop/scripts/app_startup/unlock_screen
new file mode 100755
index 0000000..478294c
--- /dev/null
+++ b/startop/scripts/app_startup/unlock_screen
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+# This turns the screen on if it's off.
+# If it's on it does nothing unless its on the home screen, in which case it opens up some background
+# menu.
+#
+# However, this menu is ignored because "am start" commands still work as expected.
+adb shell input keyevent MENU
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 8b0211e..3ad0f0c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -118,7 +119,7 @@
     }
 
     /** The unique ID of the call. */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public String getId() {
         return mId;
     }
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index 383d10b..bb066ad 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -195,6 +195,8 @@
         public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
         public static final int FILTERING_COMPLETED_TIMING = 10;
         public static final int FILTERING_TIMED_OUT_TIMING = 11;
+        /** {@hide} */
+        public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12;
 
         public static final int INVALID = 999999;
 
@@ -256,6 +258,27 @@
     public static final int SIP_PHONE = 0x8;
     public static final int THIRD_PARTY_PHONE = 0x10;
 
+    /**
+     * Indicating the call source is not specified.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_UNSPECIFIED = 0;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's dialpad.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's shortcut button.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2;
+
     public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
     public static final long MILLIS_IN_1_SECOND = 1000;
 
@@ -319,6 +342,9 @@
     // A list of video events that have occurred.
     private List<VideoEvent> videoEvents;
 
+    // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants.
+    private int callSource = CALL_SOURCE_UNSPECIFIED;
+
     public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
             boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
             int callTerminationCode, boolean isEmergencyCall, String connectionService,
@@ -356,6 +382,7 @@
         isVideoCall = readByteAsBoolean(in);
         videoEvents = new LinkedList<>();
         in.readTypedList(videoEvents, VideoEvent.CREATOR);
+        callSource = in.readInt();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -373,6 +400,7 @@
         out.writeTypedList(eventTimings);
         writeBooleanAsByte(out, isVideoCall);
         out.writeTypedList(videoEvents);
+        out.writeInt(callSource);
     }
 
     /** {@hide} */
@@ -385,6 +413,11 @@
         this.videoEvents = videoEvents;
     }
 
+    /** {@hide} */
+    public void setCallSource(int callSource) {
+        this.callSource = callSource;
+    }
+
     public long getStartTimeMillis() {
         return startTimeMillis;
     }
@@ -443,6 +476,11 @@
         return videoEvents;
     }
 
+    /** {@hide} */
+    public int getCallSource() {
+        return callSource;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 279804e..097e352 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
@@ -43,7 +44,7 @@
 public final class PhoneAccountHandle implements Parcelable {
     @UnsupportedAppUsage
     private final ComponentName mComponentName;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mId;
     private final UserHandle mUserHandle;
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 48c1e24..4e22823 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -622,6 +622,18 @@
             "android.telecom.extra.USE_ASSISTED_DIALING";
 
     /**
+     * Optional extra for {@link #placeCall(Uri, Bundle)} containing an integer that specifies
+     * the source where user initiated this call. This data is used in metrics.
+     * Valid source are:
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_UNSPECIFIED},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_DIALPAD},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_SHORTCUT}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+
+    /**
      * The following 4 constants define how properties such as phone numbers and names are
      * displayed to the user.
      */
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index ed84788..722df67 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -30,6 +30,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SqliteWrapper;
 import android.net.Uri;
+import android.os.Build;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsMessage;
@@ -374,7 +375,7 @@
          * Return cursor for table query.
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public static Cursor query(ContentResolver cr, String[] projection,
                 String where, String orderBy) {
             return cr.query(CONTENT_URI, projection, where,
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8ebfec4..b01d419 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -41,6 +41,7 @@
 import android.net.INetworkPolicyManager;
 import android.net.NetworkCapabilities;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -191,7 +192,7 @@
      * The name_source is from the user
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final int NAME_SOURCE_USER_INPUT = 2;
 
     /**
@@ -1610,7 +1611,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static boolean isValidSlotIndex(int slotIndex) {
         return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2ac0afe..fa24796 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -39,6 +39,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PersistableBundle;
@@ -702,7 +703,7 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
             "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
 
@@ -1499,23 +1500,24 @@
                 Rlog.d(TAG, "getCellLocation returning null because telephony is null");
                 return null;
             }
+
             Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
-            if (bundle.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because bundle is empty");
+            if (bundle == null || bundle.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
                 return null;
             }
+
             CellLocation cl = CellLocation.newFromBundle(bundle);
-            if (cl.isEmpty()) {
-                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty");
+            if (cl == null || cl.isEmpty()) {
+                Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
+                        + " phone type doesn't match CellLocation type");
                 return null;
             }
+
             return cl;
         } catch (RemoteException ex) {
             Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex);
             return null;
-        } catch (NullPointerException ex) {
-            Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex);
-            return null;
         }
     }
 
@@ -1690,7 +1692,7 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int getPhoneTypeFromProperty(int phoneId) {
         String type = getTelephonyProperty(phoneId,
                 TelephonyProperties.CURRENT_ACTIVE_PHONE, null);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
index 0fabc2f..541ca8d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
@@ -118,71 +118,103 @@
     public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE
             = 0x111E; // 4382
 
-    /** CMAS Message Identifier for Presidential Level alerts for additional languages
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Presidential Level alerts for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE
             = 0x111F; // 4383
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE
             = 0x1120; // 4384
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
+     *  for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE
             = 0x1121; // 4385
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE
             = 0x1122; // 4386
 
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE
             = 0x1123; // 4387
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE
             = 0x1124; // 4388
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages.*/
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE
             = 0x1125; // 4389
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE
             = 0x1126; // 4390
 
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages.*/
+    /**
+     * CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE
             = 0x1127; // 4391
 
-    /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
-     *  for additional languages. */
+    /**
+     * CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
+     * for additional languages.
+     */
     public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE
             = 0x1128; // 4392
 
-    /** CMAS Message Identifier for the Required Monthly Test
-     *  for additional languages. */
+    /** CMAS Message Identifier for the Required Monthly Test  for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE
             = 0x1129; // 4393
 
-    /** CMAS Message Identifier for CMAS Exercise
-     *  for additional languages. */
+    /** CMAS Message Identifier for CMAS Exercise for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE
             = 0x112A; // 4394
 
-    /** CMAS Message Identifier for operator defined use
-     *  for additional languages. */
+    /** CMAS Message Identifier for operator defined use for additional languages. */
     public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE
             = 0x112B; // 4395
 
+    /** CMAS Message Identifier for CMAS Public Safety Alerts. */
+    public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY
+            = 0x112C; // 4396
+
+    /** CMAS Message Identifier for CMAS Public Safety Alerts for additional languages. */
+    public static final int MESSAGE_ID_CMAS_ALERT_PUBLIC_SAFETY_LANGUAGE
+            = 0x112D; // 4397
+
+    /** CMAS Message Identifier for CMAS State/Local Test. */
+    public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST
+            = 0x112E; // 4398
+
+    /** CMAS Message Identifier for CMAS State/Local Test for additional languages. */
+    public static final int MESSAGE_ID_CMAS_ALERT_STATE_LOCAL_TEST_LANGUAGE
+            = 0x112F; // 4399
+
     /** End of CMAS Message Identifier range (including future extensions). */
     public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER
             = 0x112F; // 4399
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
index 579d972..1b63874 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Cujs.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
@@ -24,10 +24,10 @@
  * host.
  */
 public class Cujs {
-    private ITestDevice device;
+    private ITestDevice mDevice;
 
     public Cujs(ITestDevice device) {
-        this.device = device;
+        this.mDevice = device;
     }
 
     /**
@@ -38,6 +38,6 @@
         // TODO: Consider exercising the system in other interesting ways as
         // well.
         String command = "am instrument -w com.android.tests.sysmem.device/.Cujs";
-        device.executeShellCommand(command);
+        mDevice.executeShellCommand(command);
     }
 }
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
index bbec065..cfd598d 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/MemoryTest.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
@@ -22,46 +22,54 @@
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
 import com.android.tradefed.testtype.IDeviceTest;
-import java.io.IOException;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
+
+/**
+ * Runs a system memory test.
+ */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class MemoryTest implements IDeviceTest {
 
     @Rule public TestMetrics testMetrics = new TestMetrics();
     @Rule public TestLogData testLogs = new TestLogData();
 
-    private ITestDevice testDevice;
-    private int iterations = 0;     // Number of times cujs have been run.
-    private Metrics metrics;
-    private Cujs cujs;
+    private ITestDevice mTestDevice;
+    private int mIterations = 0;     // Number of times cujs have been run.
+    private Metrics mMetrics;
+    private Cujs mCujs;
 
     @Override
     public void setDevice(ITestDevice device) {
-        testDevice = device;
-        metrics = new Metrics(device, testMetrics, testLogs);
-        cujs = new Cujs(device);
+        mTestDevice = device;
+        mMetrics = new Metrics(device, testMetrics, testLogs);
+        mCujs = new Cujs(device);
     }
 
     @Override
     public ITestDevice getDevice() {
-        return testDevice;
+        return mTestDevice;
     }
 
     // Invoke a single iteration of running the cujs.
     private void runCujs() throws DeviceNotAvailableException {
-        cujs.run();
-        iterations++;
+        mCujs.run();
+        mIterations++;
     }
 
     // Sample desired memory.
     private void sample()
             throws DeviceNotAvailableException, IOException, Metrics.MetricsException {
-        metrics.sample(String.format("%03d", iterations));
+        mMetrics.sample(String.format("%03d", mIterations));
     }
 
+    /**
+     * Runs the memory tests.
+     */
     @Test
     public void run() throws Exception {
         sample();   // Sample before running cujs
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
index 616983e..70bc22c 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.tests.sysmem.host;
@@ -22,6 +22,7 @@
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -33,15 +34,15 @@
  */
 class Metrics {
 
-    private ITestDevice device;
-    private TestMetrics metrics;
-    private TestLogData logs;
+    private ITestDevice mDevice;
+    private TestMetrics mMetrics;
+    private TestLogData mLogs;
 
     /**
      * Exception thrown in case of error sampling metrics.
      */
     public static class MetricsException extends Exception {
-        public MetricsException(String msg) {
+        MetricsException(String msg) {
             super(msg);
         }
 
@@ -59,22 +60,22 @@
      * @param metrics where to log the high level metrics when taking a sample
      * @param logs where to log detailed breakdowns when taking a sample
      */
-    public Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) {
-        this.device = device;
-        this.metrics = metrics;
-        this.logs = logs;
+    Metrics(ITestDevice device, TestMetrics metrics, TestLogData logs) {
+        this.mDevice = device;
+        this.mMetrics = metrics;
+        this.mLogs = logs;
     }
 
     /**
      * Writes the given <code>text</code> to a log with the given label.
      */
     private void logText(String label, String text) throws IOException {
-      File file = File.createTempFile(label, "txt");
-      PrintStream ps = new PrintStream(file);
-      ps.print(text);
-      try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
-        logs.addTestLog(label, LogDataType.TEXT, dataStream);
-      }
+        File file = File.createTempFile(label, "txt");
+        PrintStream ps = new PrintStream(file);
+        ps.print(text);
+        try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
+            mLogs.addTestLog(label, LogDataType.TEXT, dataStream);
+        }
     }
 
     /**
@@ -82,11 +83,11 @@
      */
     private int getPidForProcess(String name)
             throws DeviceNotAvailableException, IOException, MetricsException {
-        String psout = device.executeShellCommand("ps -A -o PID,CMD");
+        String psout = mDevice.executeShellCommand("ps -A -o PID,CMD");
         Scanner sc = new Scanner(psout);
         try {
             // ps output is of the form:
-            //  PID CMD            
+            //  PID CMD
             //    1 init
             //    2 kthreadd
             //    ...
@@ -117,20 +118,22 @@
      */
     void sample(String label) throws DeviceNotAvailableException, IOException, MetricsException {
         // adb root access is required to get showmap
-        device.enableAdbRoot();
+        mDevice.enableAdbRoot();
 
         int pid = getPidForProcess("system_server");
 
         // Read showmap for system server and add it as a test log
-        String showmap = device.executeShellCommand("showmap " + pid);
+        String showmap = mDevice.executeShellCommand("showmap " + pid);
         logText(label + ".system_server.showmap", showmap);
 
         // Extract VSS, PSS and RSS from the showmap and output them as metrics.
         // The last lines of the showmap output looks something like:
+        // CHECKSTYLE:OFF Generated code
         // virtual                     shared   shared  private  private
         //    size      RSS      PSS    clean    dirty    clean    dirty     swap  swapPSS   # object
         //-------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
         //  928480   113016    24860    87348     7916     3632    14120     1968     1968 1900 TOTAL
+        // CHECKSTYLE:ON Generated code
         try {
             int pos = showmap.lastIndexOf("----");
             Scanner sc = new Scanner(showmap.substring(pos));
@@ -139,16 +142,16 @@
             long rss = sc.nextLong();
             long pss = sc.nextLong();
 
-            metrics.addTestMetric(String.format("%s.system_server.vss", label), Long.toString(vss));
-            metrics.addTestMetric(String.format("%s.system_server.rss", label), Long.toString(rss));
-            metrics.addTestMetric(String.format("%s.system_server.pss", label), Long.toString(pss));
+            mMetrics.addTestMetric(label + ".system_server.vss", Long.toString(vss));
+            mMetrics.addTestMetric(label + ".system_server.rss", Long.toString(rss));
+            mMetrics.addTestMetric(label + ".system_server.pss", Long.toString(pss));
         } catch (InputMismatchException e) {
             throw new MetricsException("unexpected showmap format", e);
         }
 
         // Run debuggerd -j to get GC stats for system server and add it as a
         // test log
-        String debuggerd = device.executeShellCommand("debuggerd -j " + pid);
+        String debuggerd = mDevice.executeShellCommand("debuggerd -j " + pid);
         logText(label + ".system_server.debuggerd", debuggerd);
 
         // TODO: Experiment with other additional metrics.
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/android/net/ip/IpServerTest.java
similarity index 71%
rename from tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
rename to tests/net/java/android/net/ip/IpServerTest.java
index 5934653..cff0b54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.connectivity.tethering;
+package android.net.ip;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -37,9 +37,9 @@
 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
+import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_TETHERED;
+import static android.net.ip.IpServer.STATE_UNAVAILABLE;
 
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
@@ -50,7 +50,6 @@
 import android.net.RouteInfo;
 import android.net.dhcp.DhcpServer;
 import android.net.dhcp.DhcpServingParams;
-import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
@@ -74,7 +73,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class TetherInterfaceStateMachineTest {
+public class IpServerTest {
     private static final String IFACE_NAME = "testnet1";
     private static final String UPSTREAM_IFACE = "upstream0";
     private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -85,39 +84,38 @@
 
     @Mock private INetworkManagementService mNMService;
     @Mock private INetworkStatsService mStatsService;
-    @Mock private IControlsTethering mTetherHelper;
+    @Mock private IpServer.Callback mCallback;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
     @Mock private SharedLog mSharedLog;
     @Mock private DhcpServer mDhcpServer;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
-    @Mock private TetheringDependencies mTetheringDependencies;
+    @Mock private IpServer.Dependencies mDependencies;
 
     @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
 
     private final TestLooper mLooper = new TestLooper();
     private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
             ArgumentCaptor.forClass(LinkProperties.class);
-    private TetherInterfaceStateMachine mTestedSm;
+    private IpServer mIpServer;
 
     private void initStateMachine(int interfaceType) throws Exception {
         initStateMachine(interfaceType, false /* usingLegacyDhcp */);
     }
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
-        mTestedSm = new TetherInterfaceStateMachine(
+        mIpServer = new IpServer(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
-                mNMService, mStatsService, mTetherHelper, usingLegacyDhcp,
-                mTetheringDependencies);
-        mTestedSm.start();
+                mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
+        mIpServer.start();
         // Starting the state machine always puts us in a consistent state and notifies
         // the rest of the world that we've changed from an unknown to available state.
         mLooper.dispatchAll();
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
-        when(mTetheringDependencies.makeDhcpServer(
+        when(mDependencies.makeDhcpServer(
                 any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
-        when(mTetheringDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
-        when(mTetheringDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+        when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
+        when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
         when(mRaDaemon.start()).thenReturn(true);
     }
@@ -130,11 +128,11 @@
     private void initTetheredStateMachine(int interfaceType, String upstreamIface,
             boolean usingLegacyDhcp) throws Exception {
         initStateMachine(interfaceType, usingLegacyDhcp);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
         if (upstreamIface != null) {
             dispatchTetherConnectionChanged(upstreamIface);
         }
-        reset(mNMService, mStatsService, mTetherHelper);
+        reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
     }
 
@@ -145,34 +143,34 @@
 
     @Test
     public void startsOutAvailable() {
-        mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
-                false /* usingLegacyDhcp */, mTetheringDependencies);
-        mTestedSm.start();
+        mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(),
+                TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mCallback,
+                false /* usingLegacyDhcp */, mDependencies);
+        mIpServer.start();
         mLooper.dispatchAll();
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mCallback, mNMService, mStatsService);
     }
 
     @Test
     public void shouldDoNothingUntilRequested() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
         final int [] NOOP_COMMANDS = {
-            TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
-            TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
-            TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
-            TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
+            IpServer.CMD_TETHER_UNREQUESTED,
+            IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
+            IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
+            IpServer.CMD_START_TETHERING_ERROR,
+            IpServer.CMD_STOP_TETHERING_ERROR,
+            IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
+            IpServer.CMD_TETHER_CONNECTION_CHANGED
         };
         for (int command : NOOP_COMMANDS) {
             // None of these commands should trigger us to request action from
             // the rest of the system.
             dispatchCommand(command);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -180,57 +178,57 @@
     public void handlesImmediateInterfaceDown() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-        verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-        verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+        verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+        verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTethered() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canUnrequestTethering() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
     public void canBeTetheredAsUsb() throws Exception {
         initStateMachine(TETHERING_USB);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder inOrder = inOrder(mTetherHelper, mNMService);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder inOrder = inOrder(mCallback, mNMService);
         inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -243,7 +241,7 @@
         InOrder inOrder = inOrder(mNMService);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -257,7 +255,7 @@
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -300,18 +298,18 @@
     public void canUnrequestTetheringWithUpstream() throws Exception {
         initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
         inOrder.verify(mStatsService).forceUpdate();
         inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
-        inOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
-        inOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), any(LinkProperties.class));
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        inOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
+        inOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), any(LinkProperties.class));
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
     }
 
     @Test
@@ -322,15 +320,15 @@
             if (shouldThrow) {
                 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
             }
-            dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+            dispatchCommand(IpServer.CMD_INTERFACE_DOWN);
+            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
             usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
             usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                     IFACE_NAME, mInterfaceConfiguration);
-            usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                    mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
-            usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                    eq(mTestedSm), mLinkPropertiesCaptor.capture());
+            usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                    mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
+            usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                    eq(mIpServer), mLinkPropertiesCaptor.capture());
             assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
         }
     }
@@ -340,15 +338,15 @@
         initStateMachine(TETHERING_USB);
 
         doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
-        dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                 IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -358,13 +356,13 @@
 
         doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mCallback);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
-        usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
-                mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
-        usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
-                eq(mTestedSm), mLinkPropertiesCaptor.capture());
+        usbTeardownOrder.verify(mCallback).updateInterfaceState(
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
+        usbTeardownOrder.verify(mCallback).updateLinkProperties(
+                eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
     }
 
@@ -372,11 +370,11 @@
     public void ignoresDuplicateUpstreamNotifications() throws Exception {
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
 
-        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
 
         for (int i = 0; i < 5; i++) {
             dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+            verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
         }
     }
 
@@ -401,11 +399,11 @@
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
 
-        verify(mTetheringDependencies, never()).makeDhcpServer(any(), any(), any(), any());
+        verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
     }
 
     private void assertDhcpStarted(IpPrefix expectedPrefix) {
-        verify(mTetheringDependencies, times(1)).makeDhcpServer(
+        verify(mDependencies, times(1)).makeDhcpServer(
                 eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
         verify(mDhcpServer, times(1)).start();
         final DhcpServingParams params = mDhcpParamsCaptor.getValue();
@@ -422,21 +420,21 @@
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      * @param arg1 An additional argument to pass.
      */
     private void dispatchCommand(int command, int arg1) {
-        mTestedSm.sendMessage(command, arg1);
+        mIpServer.sendMessage(command, arg1);
         mLooper.dispatchAll();
     }
 
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
-     * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
+     * @param command One of the IpServer.CMD_* constants.
      */
     private void dispatchCommand(int command) {
-        mTestedSm.sendMessage(command);
+        mIpServer.sendMessage(command);
         mLooper.dispatchAll();
     }
 
@@ -447,7 +445,7 @@
      * @param upstreamIface String name of upstream interface (or null)
      */
     private void dispatchTetherConnectionChanged(String upstreamIface) {
-        mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+        mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
                 new InterfaceSet(upstreamIface));
         mLooper.dispatchAll();
     }
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 102cb7c..99a5a69 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -41,9 +41,9 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
-import android.test.mock.MockContext;
 import android.support.test.filters.SmallTest;
 import android.system.Os;
+import android.test.mock.MockContext;
 
 import java.net.Socket;
 import java.util.Arrays;
@@ -121,6 +121,7 @@
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
     Network fakeNetwork = new Network(0xAB);
+    int mUid = Os.getuid();
 
     private static final IpSecAlgorithm AUTH_ALGO =
             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
@@ -181,7 +182,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -189,8 +190,7 @@
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
         try {
             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
@@ -209,8 +209,7 @@
                 mIpSecService.allocateSecurityParameterIndex(
                         mDestinationAddr, TEST_SPI, new Binder());
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
 
@@ -218,7 +217,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -270,7 +269,7 @@
 
         verify(mMockNetd)
                 .ipSecAddSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyInt(),
                         anyString(),
                         anyString(),
@@ -305,7 +304,7 @@
 
         verify(mMockNetd)
                 .ipSecAddSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyInt(),
                         anyString(),
                         anyString(),
@@ -361,13 +360,12 @@
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
         verify(mMockNetd, times(0))
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -389,7 +387,7 @@
 
         verify(mMockNetd, times(1))
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -397,8 +395,7 @@
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
 
@@ -433,8 +430,7 @@
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
                         createTransformResp.resourceId);
@@ -443,7 +439,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -477,7 +473,7 @@
         verify(mMockNetd)
                 .ipSecApplyTransportModeTransform(
                         eq(pfd.getFileDescriptor()),
-                        eq(resourceId),
+                        eq(mUid),
                         eq(IpSecManager.DIRECTION_OUT),
                         anyString(),
                         anyString(),
@@ -509,8 +505,7 @@
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
         // Check that we have stored the tracking object, and retrieve it
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                         createTunnelResp.resourceId);
@@ -530,8 +525,7 @@
         IpSecTunnelInterfaceResponse createTunnelResp =
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
 
         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
 
@@ -551,8 +545,7 @@
         IpSecTunnelInterfaceResponse createTunnelResp =
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                         createTunnelResp.resourceId);
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 0d3b8e4..40d5544 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -75,6 +75,7 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
 import android.net.util.NetworkConstants;
@@ -99,10 +100,8 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 
@@ -190,7 +189,7 @@
 
     public class MockTetheringDependencies extends TetheringDependencies {
         StateMachine upstreamNetworkMonitorMasterSM;
-        ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+        ArrayList<IpServer> ipv6CoordinatorNotifyList;
         int isTetheringSupportedCalls;
 
         public void reset() {
@@ -213,29 +212,35 @@
 
         @Override
         public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-                ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log) {
+                ArrayList<IpServer> notifyList, SharedLog log) {
             ipv6CoordinatorNotifyList = notifyList;
             return mIPv6TetheringCoordinator;
         }
 
         @Override
-        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
-            return mRouterAdvertisementDaemon;
-        }
+        public IpServer.Dependencies getIpServerDependencies() {
+            return new IpServer.Dependencies() {
+                @Override
+                public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+                        InterfaceParams ifParams) {
+                    return mRouterAdvertisementDaemon;
+                }
 
-        @Override
-        public INetd getNetdService() {
-            return mNetd;
-        }
+                @Override
+                public InterfaceParams getInterfaceParams(String ifName) {
+                    final String[] ifaces = new String[] {
+                            TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+                    final int index = ArrayUtils.indexOf(ifaces, ifName);
+                    assertTrue("Non-mocked interface: " + ifName, index >= 0);
+                    return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
+                            MacAddress.ALL_ZEROS_ADDRESS);
+                }
 
-        @Override
-        public InterfaceParams getInterfaceParams(String ifName) {
-            final String[] ifaces = new String[] { TEST_USB_IFNAME, TEST_WLAN_IFNAME,
-                    TEST_MOBILE_IFNAME };
-            final int index = ArrayUtils.indexOf(ifaces, ifName);
-            assertTrue("Non-mocked interface: " + ifName, index >= 0);
-            return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
-                    MacAddress.ALL_ZEROS_ADDRESS);
+                @Override
+                public INetd getNetdService() {
+                    return mNetd;
+                }
+            };
         }
 
         @Override
@@ -458,9 +463,9 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        // If, and only if, Tethering received an interface status changed
-        // then it creates a TetherInterfaceStateMachine and sends out a
-        // broadcast indicating that the interface is "available".
+        // If, and only if, Tethering received an interface status changed then
+        // it creates a IpServer and sends out a broadcast indicating that the
+        // interface is "available".
         if (emulateInterfaceStatusChanged) {
             assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
             verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
@@ -557,18 +562,18 @@
     }
 
     /**
-     * Send CMD_IPV6_TETHER_UPDATE to TISMs as would be done by IPv6TetheringCoordinator.
+     * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
      */
     private void sendIPv6TetherUpdates(NetworkState upstreamState) {
         // IPv6TetheringCoordinator must have been notified of downstream
         verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
                 argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
-                eq(IControlsTethering.STATE_TETHERED));
+                eq(IpServer.STATE_TETHERED));
 
-        for (TetherInterfaceStateMachine tism :
+        for (IpServer ipSrv :
                 mTetheringDependencies.ipv6CoordinatorNotifyList) {
             NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
-            tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
+            ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
                     upstreamState.linkProperties.isIPv6Provisioned()
                             ? ipv6OnlyState.linkProperties
                             : null);
@@ -812,7 +817,7 @@
 
         // We verify get/set called thrice here: once for setup and twice during
         // teardown because all events happen over the course of the single
-        // dispatchAll() above. Note that once the TISM IPv4 address config
+        // dispatchAll() above. Note that once the IpServer IPv4 address config
         // code is refactored the two calls during shutdown will revert to one.
         verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
         verify(mNMService, times(3))
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 50e8b33..30deb55 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -133,11 +133,19 @@
   void Log(Level level, DiagMessageActual& actual_msg) override {
     actual_msg.source.path = source_.path;
     diag_->Log(level, actual_msg);
+    if (level == Level::Error) {
+      error = true;
+    }
+  }
+
+  bool HadError() {
+    return error;
   }
 
  private:
   Source source_;
   IDiagnostics* diag_;
+  bool error = false;
 
   DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
 };
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 0778564..9a7238b 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -303,7 +303,7 @@
   }
 }
 
-TEST(StringPoolTest, FlattenModifiedUTF8) {
+TEST(StringPoolTest, ModifiedUTF8) {
   using namespace android;  // For NO_ERROR on Windows.
   StdErrDiagnostics diag;
   StringPool pool;
@@ -315,12 +315,24 @@
   StringPool::FlattenUtf8(&buffer, pool, &diag);
   std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
 
-  // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs
+  // Check that the codepoints are encoded using two three-byte surrogate pairs
   ResStringPool test;
   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
-  EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80"));
-  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
-  EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+  size_t len;
+  const char* str = test.string8At(0, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80"));
+  str = test.string8At(1, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+  str = test.string8At(2, &len);
+  ASSERT_THAT(str, NotNull());
+  EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+
+  // Check that retrieving the strings returns the original UTF-8 character bytes
+  EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
+  EXPECT_THAT(util::GetString(test, 1), Eq("foo \xF0\x90\x90\xB7 bar"));
+  EXPECT_THAT(util::GetString(test, 2), Eq("\xF0\x90\x90\x80\xF0\x90\x90\xB7"));
 }
 
 TEST(StringPoolTest, MaxEncodingLength) {
diff --git a/tools/aapt2/compile/XmlIdCollector.cpp b/tools/aapt2/compile/XmlIdCollector.cpp
index d61a15a..2199d00 100644
--- a/tools/aapt2/compile/XmlIdCollector.cpp
+++ b/tools/aapt2/compile/XmlIdCollector.cpp
@@ -21,6 +21,7 @@
 
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
+#include "text/Unicode.h"
 #include "xml/XmlDom.h"
 
 namespace aapt {
@@ -35,8 +36,9 @@
  public:
   using xml::Visitor::Visit;
 
-  explicit IdCollector(std::vector<SourcedResourceName>* out_symbols)
-      : out_symbols_(out_symbols) {}
+  explicit IdCollector(std::vector<SourcedResourceName>* out_symbols,
+                       SourcePathDiagnostics* source_diag) : out_symbols_(out_symbols),
+                                                             source_diag_(source_diag) {}
 
   void Visit(xml::Element* element) override {
     for (xml::Attribute& attr : element->attributes) {
@@ -44,12 +46,16 @@
       bool create = false;
       if (ResourceUtils::ParseReference(attr.value, &name, &create, nullptr)) {
         if (create && name.type == ResourceType::kId) {
-          auto iter = std::lower_bound(out_symbols_->begin(),
-                                       out_symbols_->end(), name, cmp_name);
-          if (iter == out_symbols_->end() || iter->name != name) {
-            out_symbols_->insert(iter,
-                                 SourcedResourceName{name.ToResourceName(),
-                                                     element->line_number});
+          if (!text::IsValidResourceEntryName(name.entry)) {
+            source_diag_->Error(DiagMessage(element->line_number)
+                                   << "id '" << name << "' has an invalid entry name");
+          } else {
+            auto iter = std::lower_bound(out_symbols_->begin(),
+                                         out_symbols_->end(), name, cmp_name);
+            if (iter == out_symbols_->end() || iter->name != name) {
+              out_symbols_->insert(iter, SourcedResourceName{name.ToResourceName(),
+                                                             element->line_number});
+            }
           }
         }
       }
@@ -60,15 +66,17 @@
 
  private:
   std::vector<SourcedResourceName>* out_symbols_;
+  SourcePathDiagnostics* source_diag_;
 };
 
 }  // namespace
 
 bool XmlIdCollector::Consume(IAaptContext* context, xml::XmlResource* xmlRes) {
   xmlRes->file.exported_symbols.clear();
-  IdCollector collector(&xmlRes->file.exported_symbols);
+  SourcePathDiagnostics source_diag(xmlRes->file.source, context->GetDiagnostics());
+  IdCollector collector(&xmlRes->file.exported_symbols, &source_diag);
   xmlRes->root->Accept(&collector);
-  return true;
+  return !source_diag.HadError();
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 98da56d..d49af3b 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -64,4 +64,14 @@
   EXPECT_TRUE(doc->file.exported_symbols.empty());
 }
 
+TEST(XmlIdCollectorTest, ErrorOnInvalidIds) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::unique_ptr<xml::XmlResource> doc =
+      test::BuildXmlDom("<View foo=\"@+id/foo$bar\"/>");
+
+  XmlIdCollector collector;
+  ASSERT_FALSE(collector.Consume(context.get(), doc.get()));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index c5c78d9..fa6538d 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -252,6 +252,7 @@
   xml::XmlNodeAction component_action;
   component_action.Action(RequiredNameIsJavaClassName);
   component_action["intent-filter"] = intent_filter_action;
+  component_action["preferred"] = intent_filter_action;
   component_action["meta-data"] = meta_data_action;
 
   // Manifest actions.
@@ -414,6 +415,8 @@
   application_action["provider"]["grant-uri-permission"];
   application_action["provider"]["path-permission"];
 
+  manifest_action["package"] = manifest_action;
+
   return true;
 }
 
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 7cd023b..73105e16 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -102,12 +102,25 @@
 #endif
 
 bool mkdirs(const std::string& path) {
-  constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
+  #ifdef _WIN32
+  // Start after the drive path if present. Calling mkdir with only the drive will cause an error.
+  size_t current_pos = 1u;
+  if (path.size() >= 3 && path[1] == ':' &&
+        (path[2] == '\\' || path[2] == '/')) {
+    current_pos = 3u;
+  }
+ #else
   // Start after the first character so that we don't consume the root '/'.
   // This is safe to do with unicode because '/' will never match with a continuation character.
   size_t current_pos = 1u;
+ #endif
+  constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
   while ((current_pos = path.find(sDirSep, current_pos)) != std::string::npos) {
     std::string parent_path = path.substr(0, current_pos);
+    if (parent_path.empty()) {
+      continue;
+    }
+
     int result = ::android::base::utf8::mkdir(parent_path.c_str(), mode);
     if (result < 0 && errno != EEXIST) {
       return false;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 9bef54e5..59b7fff 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -322,11 +322,11 @@
   output.reserve(modified_size);
   for (size_t i = 0; i < size; i++) {
     if (((uint8_t) utf8[i] >> 4) == 0xF) {
-      auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr);
+      int32_t codepoint = utf32_from_utf8_at(utf8.data(), size, i, nullptr);
 
       // Calculate the high and low surrogates as UTF-16 would
-      char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
-      char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
+      int32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800;
+      int32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
 
       // Encode each surrogate in UTF-8
       output.push_back((char) (0xE4 | ((high >> 12) & 0xF)));
@@ -344,6 +344,60 @@
   return output;
 }
 
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
+  // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
+  // representation.
+  std::string output;
+  output.reserve(modified_utf8.size());
+
+  size_t index = 0;
+  const size_t modified_size = modified_utf8.size();
+  while (index < modified_size) {
+    size_t next_index;
+    int32_t high_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, index,
+                                                &next_index);
+    if (high_surrogate < 0) {
+      return {};
+    }
+
+    // Check that the first codepoint is within the high surrogate range
+    if (high_surrogate >= 0xD800 && high_surrogate <= 0xDB7F) {
+      int32_t low_surrogate = utf32_from_utf8_at(modified_utf8.data(), modified_size, next_index,
+                                                 &next_index);
+      if (low_surrogate < 0) {
+        return {};
+      }
+
+      // Check that the second codepoint is within the low surrogate range
+      if (low_surrogate >= 0xDC00 && low_surrogate <= 0xDFFF) {
+        const char32_t codepoint = (char32_t) (((high_surrogate - 0xD800) * 0x400)
+            + (low_surrogate - 0xDC00) + 0x10000);
+
+        // The decoded codepoint should represent a 4 byte, UTF-8 character
+        const size_t utf8_length = (size_t) utf32_to_utf8_length(&codepoint, 1);
+        if (utf8_length != 4) {
+          return {};
+        }
+
+        // Encode the UTF-8 representation of the codepoint into the string
+        char* start = &output[output.size()];
+        output.resize(output.size() + utf8_length);
+        utf32_to_utf8((char32_t*) &codepoint, 1, start, utf8_length + 1);
+
+        index = next_index;
+        continue;
+      }
+    }
+
+    // Append non-surrogate pairs to the output string
+    for (size_t i = index; i < next_index; i++) {
+      output.push_back(modified_utf8[i]);
+    }
+    index = next_index;
+  }
+  return output;
+}
+
 std::u16string Utf8ToUtf16(const StringPiece& utf8) {
   ssize_t utf16_length = utf8_to_utf16_length(
       reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
@@ -469,7 +523,7 @@
   size_t len;
   const char* str = pool.string8At(idx, &len);
   if (str != nullptr) {
-    return std::string(str, len);
+    return ModifiedUtf8ToUtf8(std::string(str, len));
   }
   return Utf16ToUtf8(GetString16(pool, idx));
 }
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 36b7333..c6e8e6e 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -199,6 +199,7 @@
 
 // Converts a UTF8 string into Modified UTF8
 std::string Utf8ToModifiedUtf8(const std::string& utf8);
+std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
 
 // Converts a UTF8 string to a UTF16 string.
 std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 018e9c9..934847f 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -697,8 +697,8 @@
         "android.provider",
         ["android.content","android.graphics.drawable"],
         "android.database",
-        "android.graphics",
         "android.text",
+        "android.graphics",
         "android.os",
         "android.util"
     ]
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index bdcc807..76a2f2d 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -12,8 +12,8 @@
 # Sort
 IFS=$'\n'
 # Stash away comments
-C=( $(grep -E '^#' <<< "${A[*]}") )
-A=( $(grep -v -E '^#' <<< "${A[*]}") )
+C=( $(grep -E '^#' <<< "${A[*]}" || :) )
+A=( $(grep -v -E '^#' <<< "${A[*]}" || :) )
 # Sort entries
 A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
 A=( $(uniq <<< "${A[*]}") )
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 57f3973..5a4c898 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -30,6 +30,7 @@
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo;
 import android.net.wifi.p2p.nsd.WifiP2pUpnpServiceResponse;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -488,7 +489,7 @@
      * @hide - hide this because it takes in a parameter of type IWifiP2pManager, which
      * is a system private class.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public WifiP2pManager(IWifiP2pManager service) {
         mService = service;
     }