Merge "Shell: Allow usage of UwbManager APIs"
diff --git a/Android.bp b/Android.bp
index 0b0a9b7..084c9f5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -252,42 +252,6 @@
     installable: false,
 }
 
-filegroup {
-    name: "framework-jarjar-rules",
-    srcs: ["framework-jarjar-rules.txt"],
-}
-
-filegroup {
-    name: "libincident_aidl",
-    srcs: [
-        "core/java/android/os/IIncidentDumpCallback.aidl",
-        "core/java/android/os/IIncidentManager.aidl",
-        "core/java/android/os/IIncidentReportStatusListener.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "libvibrator_aidl",
-    srcs: [
-        "core/java/android/os/IExternalVibrationController.aidl",
-        "core/java/android/os/IExternalVibratorService.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "libpowermanager_aidl",
-    srcs: [
-        "core/java/android/os/Temperature.aidl",
-        "core/java/android/os/CoolingDevice.aidl",
-        "core/java/android/os/IThermalEventListener.aidl",
-        "core/java/android/os/IThermalStatusListener.aidl",
-        "core/java/android/os/IThermalService.aidl",
-    ],
-    path: "core/java",
-}
-
 java_library {
     name: "framework-minus-apex",
     defaults: ["framework-aidl-export-defaults"],
@@ -304,7 +268,7 @@
         "--multi-dex",
     ],
     installable: true,
-    jarjar_rules: ":framework-jarjar-rules",
+    jarjar_rules: "framework-jarjar-rules.txt",
     javac_shard_size: 150,
     plugins: [
         "view-inspector-annotation-processor",
@@ -376,84 +340,6 @@
     src: ":framework-minus-apex",
 }
 
-genrule {
-    name: "statslog-framework-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
-        " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
-    out: ["com/android/internal/util/FrameworkStatsLog.java"],
-}
-
-java_library {
-    name: "uieventloggerlib",
-    srcs: [
-        "core/java/com/android/internal/logging/UiEvent.java",
-        "core/java/com/android/internal/logging/UiEventLogger.java",
-        "core/java/com/android/internal/logging/UiEventLoggerImpl.java",
-        "core/java/com/android/internal/logging/InstanceId.java",
-        "core/java/com/android/internal/logging/InstanceIdSequence.java",
-        ":statslog-framework-java-gen",
-    ],
-}
-
-gensrcs {
-    name: "framework-javastream-protos",
-    depfile: true,
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-javastream",
-        "soong_zip",
-    ],
-
-    cmd: "mkdir -p $(genDir)/$(in) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-javastream) " +
-        "  --dependency_out=$(depfile) " +
-        "  --javastream_out=$(genDir)/$(in) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in) " +
-        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        ":libtombstone_proto-src",
-        "core/proto/**/*.proto",
-        "libs/incident/**/*.proto",
-    ],
-    output_extension: "srcjar",
-}
-
-gensrcs {
-    name: "framework-cppstream-protos",
-    depfile: true,
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-cppstream",
-    ],
-
-    cmd: "mkdir -p $(genDir) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-cppstream) " +
-        "  --dependency_out=$(depfile) " +
-        "  --cppstream_out=$(genDir) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in)",
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        "core/proto/**/*.proto",
-        "libs/incident/**/*.proto",
-    ],
-
-    output_extension: "proto.h",
-}
-
 filegroup {
     name: "framework-annotations",
     srcs: [
@@ -528,30 +414,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-services-net-module-wifi-shared-srcs",
-    srcs: [
-        "core/java/android/net/DhcpResults.java",
-        "core/java/android/util/LocalLog.java",
-    ],
-}
-
-// keep these files in sync with the package/Tethering/jarjar-rules.txt and
-// package/Connectivity/jarjar-rules.txt for the tethering module and connectivity module.
-filegroup {
-    name: "framework-connectivity-shared-srcs",
-    srcs: [
-        "core/java/android/util/LocalLog.java",
-        // This should be android.util.IndentingPrintWriter, but it's not available in all branches.
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/MessageUtils.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/WakeupMessage.java",
-    ],
-}
-
 // Build ext.jar
 // ============================================================
 java_library {
@@ -566,371 +428,6 @@
     dxflags: ["--core-library"],
 }
 
-// ====  java proto host library  ==============================
-java_library_host {
-    name: "platformprotos",
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        ":libstats_internal_protos",
-        ":statsd_internal_protos",
-        "cmds/am/proto/instrumentation_data.proto",
-        "cmds/statsd/src/**/*.proto",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/**/*.proto",
-    ],
-    proto: {
-        include_dirs: [
-            "external/protobuf/src",
-            "frameworks/proto_logging/stats",
-        ],
-        type: "full",
-    },
-    errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
-    },
-}
-
-// ====  java proto device library (for test only)  ==============================
-java_library {
-    name: "platformprotosnano",
-    proto: {
-        type: "nano",
-        output_params: ["store_unknown_fields=true"],
-        include_dirs: ["external/protobuf/src"],
-    },
-    exclude_srcs: [
-        "core/proto/android/privacy.proto",
-        "core/proto/android/section.proto",
-    ],
-    sdk_version: "9",
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/android/os/**/*.proto",
-    ],
-}
-
-// ====  java proto device library (for test only)  ==============================
-java_library {
-    name: "platformprotoslite",
-    proto: {
-        type: "lite",
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/android/os/**/*.proto",
-    ],
-    exclude_srcs: [
-        "core/proto/android/privacy.proto",
-        "core/proto/android/section.proto",
-    ],
-    sdk_version: "core_current",
-    // Protos have lots of MissingOverride and similar.
-    errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
-    },
-}
-
-// ====  c++ proto device library  ==============================
-cc_defaults {
-    name: "libplatformprotos-defaults",
-
-    proto: {
-        export_proto_headers: true,
-        include_dirs: [
-            "external/protobuf/src",
-        ],
-    },
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        ":libstats_atom_enum_protos",
-        "core/proto/**/*.proto",
-    ],
-}
-
-cc_library {
-    name: "libplatformprotos",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: true,
-
-    target: {
-        host: {
-            proto: {
-                type: "full",
-            },
-        },
-        android: {
-            proto: {
-                type: "lite",
-            },
-            shared_libs: [
-                "libprotobuf-cpp-lite",
-            ],
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-// This library is meant for vendor code that needs to output protobuf. It links
-// against the static version of libprotobuf-cpp-lite, for which we can not guarantee
-// binary compatibility.
-cc_library {
-    name: "libplatformprotos-static",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: false,
-
-    // This is okay because this library is only built as a static library.  The C++
-    // API is not guaranteed. The proto API is guaranteed to be stable via Metrics Council,
-    // but is not authorized to be used outside of debugging.
-    vendor_available: true,
-
-    target: {
-        android: {
-            proto: {
-                type: "lite",
-            },
-            static_libs: [
-                "libprotobuf-cpp-lite",
-            ],
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-// This is the full proto version of libplatformprotos. It may only
-// be used by test code that is not shipped on the device.
-cc_library {
-    name: "libplatformprotos-test",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: false,
-
-    target: {
-        android: {
-            proto: {
-                type: "full",
-            },
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-filegroup {
-    name: "incremental_aidl",
-    srcs: [
-        "core/java/android/os/incremental/IIncrementalServiceConnector.aidl",
-        "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "dataloader_aidl",
-    srcs: [
-        "core/java/android/content/pm/DataLoaderParamsParcel.aidl",
-        "core/java/android/content/pm/DataLoaderType.aidl",
-        "core/java/android/content/pm/FileSystemControlParcel.aidl",
-        "core/java/android/content/pm/IDataLoader.aidl",
-        "core/java/android/content/pm/IDataLoaderManager.aidl",
-        "core/java/android/content/pm/InstallationFileParcel.aidl",
-        "core/java/android/content/pm/InstallationFileLocation.aidl",
-        "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
-        "core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "incremental_manager_aidl",
-    srcs: [
-        "core/java/android/os/incremental/IIncrementalService.aidl",
-        "core/java/android/os/incremental/IncrementalNewFileParams.aidl",
-        "core/java/android/os/incremental/IStorageHealthListener.aidl",
-        "core/java/android/os/incremental/StorageHealthCheckParams.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "activity_manager_procstate_aidl",
-    srcs: [
-        // internal only
-    ],
-    path: "core/java",
-}
-
-aidl_interface {
-    name: "libincremental_aidl",
-    unstable: true,
-    srcs: [
-        ":incremental_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: true,
-        },
-    },
-}
-
-aidl_interface {
-    name: "libdataloader_aidl",
-    unstable: true,
-    srcs: [
-        ":dataloader_aidl",
-    ],
-    imports: [
-        "libincremental_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: false,
-        },
-    },
-}
-
-aidl_interface {
-    name: "libincremental_manager_aidl",
-    unstable: true,
-    srcs: [
-        ":incremental_manager_aidl",
-    ],
-    imports: [
-        "libincremental_aidl",
-        "libdataloader_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: false,
-        },
-    },
-}
-
-// Build Rust bindings for PermissionController. Needed by keystore2.
-aidl_interface {
-    name: "android.os.permissions_aidl",
-    unstable: true,
-    local_include_dir: "core/java",
-    srcs: [
-        "core/java/android/os/IPermissionController.aidl",
-    ],
-    backend: {
-        rust: {
-            enabled: true,
-        },
-    },
-}
-
-python_defaults {
-    name: "base_default",
-    version: {
-        py2: {
-            enabled: false,
-            embedded_launcher: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
-}
-
-python_binary_host {
-    name: "fontchain_linter",
-    defaults: ["base_default"],
-    main: "tools/fonts/fontchain_linter.py",
-    srcs: [
-        "tools/fonts/fontchain_linter.py",
-    ],
-    libs: [
-        "fontTools",
-    ],
-}
-
-// Avoid including Parcelable classes as we don't want to have two copies of
-// Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
-// and TeleService app (packages/services/Telephony).
-filegroup {
-    name: "framework-telephony-common-shared-srcs",
-    srcs: [
-        "core/java/android/os/RegistrantList.java",
-        "core/java/android/os/Registrant.java",
-        "core/java/android/util/LocalLog.java",
-        "core/java/android/util/TimeUtils.java",
-        "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/AsyncChannel.java",
-        "core/java/com/android/internal/util/AsyncService.java",
-        "core/java/com/android/internal/util/BitwiseInputStream.java",
-        "core/java/com/android/internal/util/FastXmlSerializer.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/UserIcons.java",
-    ],
-}
-
-// Avoid including Parcelable classes as we don't want to have two copies of
-// Parcelable cross the process.
-filegroup {
-    name: "framework-cellbroadcast-shared-srcs",
-    srcs: [
-        "core/java/android/os/HandlerExecutor.java",
-        "core/java/android/util/LocalLog.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-    ],
-}
-
-filegroup {
-    name: "framework-ims-common-shared-srcs",
-    srcs: [
-        "core/java/android/os/RegistrantList.java",
-        "core/java/android/os/Registrant.java",
-        "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-    ],
-}
-
 // utility classes statically linked into framework-wifi and dynamically linked
 // into wifi-service
 java_library {
@@ -959,33 +456,6 @@
     ],
 }
 
-filegroup {
-    name: "framework-wifi-util-lib-aidls",
-    srcs: ["core/java/android/content/pm/ParceledListSlice.aidl"],
-    path: "core/java",
-}
-
-// utility classes statically linked into wifi-service
-filegroup {
-    name: "framework-wifi-service-shared-srcs",
-    srcs: [
-        "core/java/android/net/InterfaceConfiguration.java",
-        "core/java/android/util/BackupUtils.java",
-        "core/java/android/util/Rational.java",
-        "core/java/com/android/internal/util/FastXmlSerializer.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/MessageUtils.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/WakeupMessage.java",
-    ],
-    visibility: [
-        "//frameworks/opt/net/wifi/service",
-        "//packages/modules/Wifi/service",
-    ],
-}
-
 // TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
     "--hide-package com.android.server " +
@@ -1019,4 +489,5 @@
 build = [
     "StubLibraries.bp",
     "ApiDocs.bp",
+    "ProtoLibraries.bp",
 ]
diff --git a/OWNERS b/OWNERS
index 710f13e..4970dd1 100644
--- a/OWNERS
+++ b/OWNERS
@@ -30,3 +30,4 @@
 per-file Android.mk = file:platform/build/soong:/OWNERS
 per-file ApiDocs.bp = file:platform/build/soong:/OWNERS
 per-file StubLibraries.bp = file:platform/build/soong:/OWNERS
+per-file ProtoLibraries.bp = file:platform/build/soong:/OWNERS
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
new file mode 100644
index 0000000..c127449
--- /dev/null
+++ b/ProtoLibraries.bp
@@ -0,0 +1,238 @@
+// Copyright (C) 2021 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.
+
+gensrcs {
+    name: "framework-javastream-protos",
+    depfile: true,
+
+    tools: [
+        "aprotoc",
+        "protoc-gen-javastream",
+        "soong_zip",
+    ],
+
+    cmd: "mkdir -p $(genDir)/$(in) " +
+        "&& $(location aprotoc) " +
+        "  --plugin=$(location protoc-gen-javastream) " +
+        "  --dependency_out=$(depfile) " +
+        "  --javastream_out=$(genDir)/$(in) " +
+        "  -Iexternal/protobuf/src " +
+        "  -I . " +
+        "  $(in) " +
+        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libtombstone_proto-src",
+        "core/proto/**/*.proto",
+        "libs/incident/**/*.proto",
+    ],
+    output_extension: "srcjar",
+}
+
+gensrcs {
+    name: "framework-cppstream-protos",
+    depfile: true,
+
+    tools: [
+        "aprotoc",
+        "protoc-gen-cppstream",
+    ],
+
+    cmd: "mkdir -p $(genDir) " +
+        "&& $(location aprotoc) " +
+        "  --plugin=$(location protoc-gen-cppstream) " +
+        "  --dependency_out=$(depfile) " +
+        "  --cppstream_out=$(genDir) " +
+        "  -Iexternal/protobuf/src " +
+        "  -I . " +
+        "  $(in)",
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/**/*.proto",
+    ],
+
+    output_extension: "proto.h",
+}
+
+// ====  java proto host library  ==============================
+java_library_host {
+    name: "platformprotos",
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_internal_protos",
+        ":statsd_internal_protos",
+        "cmds/am/proto/instrumentation_data.proto",
+        "cmds/statsd/src/**/*.proto",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/**/*.proto",
+    ],
+    proto: {
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
+        type: "full",
+    },
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
+    },
+}
+
+// ====  java proto device library (for test only)  ==============================
+java_library {
+    name: "platformprotosnano",
+    proto: {
+        type: "nano",
+        output_params: ["store_unknown_fields=true"],
+        include_dirs: ["external/protobuf/src"],
+    },
+    exclude_srcs: [
+        "core/proto/android/privacy.proto",
+        "core/proto/android/section.proto",
+    ],
+    sdk_version: "9",
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/android/os/**/*.proto",
+    ],
+}
+
+// ====  java proto device library (for test only)  ==============================
+java_library {
+    name: "platformprotoslite",
+    proto: {
+        type: "lite",
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/android/os/**/*.proto",
+    ],
+    exclude_srcs: [
+        "core/proto/android/privacy.proto",
+        "core/proto/android/section.proto",
+    ],
+    sdk_version: "core_current",
+    // Protos have lots of MissingOverride and similar.
+    errorprone: {
+        javacflags: ["-XepDisableAllChecks"],
+    },
+}
+
+// ====  c++ proto device library  ==============================
+cc_defaults {
+    name: "libplatformprotos-defaults",
+
+    proto: {
+        export_proto_headers: true,
+        include_dirs: [
+            "external/protobuf/src",
+        ],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        "core/proto/**/*.proto",
+    ],
+}
+
+cc_library {
+    name: "libplatformprotos",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: true,
+
+    target: {
+        host: {
+            proto: {
+                type: "full",
+            },
+        },
+        android: {
+            proto: {
+                type: "lite",
+            },
+            shared_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
+
+// This library is meant for vendor code that needs to output protobuf. It links
+// against the static version of libprotobuf-cpp-lite, for which we can not guarantee
+// binary compatibility.
+cc_library {
+    name: "libplatformprotos-static",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: false,
+
+    // This is okay because this library is only built as a static library.  The C++
+    // API is not guaranteed. The proto API is guaranteed to be stable via Metrics Council,
+    // but is not authorized to be used outside of debugging.
+    vendor_available: true,
+
+    target: {
+        android: {
+            proto: {
+                type: "lite",
+            },
+            static_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
+
+// This is the full proto version of libplatformprotos. It may only
+// be used by test code that is not shipped on the device.
+cc_library {
+    name: "libplatformprotos-test",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: false,
+
+    target: {
+        android: {
+            proto: {
+                type: "full",
+            },
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 41cbb6a..fa97203 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -111,7 +111,7 @@
         last_released: {
             api_file: ":android-non-updatable.api.public.latest",
             removed_api_file: ":android-non-updatable-removed.api.public.latest",
-            baseline_file: ":android-incompatibilities.api.public.latest",
+            baseline_file: ":android-non-updatable-incompatibilities.api.public.latest",
         },
         api_lint: {
             enabled: true,
@@ -120,13 +120,19 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/public/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/public/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -134,21 +140,18 @@
     ],
 }
 
-priv_apps =
-    " --show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
     "\\)"
 
-priv_apps_in_stubs =
-    " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
     "\\)"
 
 test = " --show-annotation android.annotation.TestApi"
 
-module_libs =
-    " --show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+module_libs = " --show-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
     "\\)"
 
 droidstubs {
@@ -163,7 +166,7 @@
         last_released: {
             api_file: ":android-non-updatable.api.system.latest",
             removed_api_file: ":android-non-updatable-removed.api.system.latest",
-            baseline_file: ":android-incompatibilities.api.system.latest"
+            baseline_file: ":android-non-updatable-incompatibilities.api.system.latest",
         },
         api_lint: {
             enabled: true,
@@ -173,13 +176,19 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/system/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -203,25 +212,37 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/test/api",
             dest: "android.txt",
             tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/test/api",
             dest: "removed.txt",
             tag: ".removed-api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/test/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/test/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -249,13 +270,19 @@
     },
     dists: [
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/module-lib/api",
             dest: "android-non-updatable.txt",
             tag: ".api.txt",
         },
         {
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             dir: "apistubs/android/module-lib/api",
             dest: "android-non-updatable-removed.txt",
             tag: ".removed-api.txt",
@@ -302,20 +329,18 @@
     name: "android-non-updatable_defaults_stubs_current",
     libs: ["stub-annotations"],
     static_libs: ["framework-res-package-jar"], // Export package of framework-res
-    errorprone: {
-        javacflags: [
-            "-XepDisableAllChecks",
-        ],
-    },
     sdk_version: "none",
     system_modules: "none",
     java_version: "1.8",
     compile_dex: true,
     dist: {
-        targets: ["sdk", "win_sdk"],
+        targets: [
+            "sdk",
+            "win_sdk",
+        ],
         tag: ".jar",
         dest: "android-non-updatable.jar",
-    }
+    },
 }
 
 java_library_static {
@@ -331,7 +356,7 @@
 java_library_static {
     name: "android-non-updatable.stubs.system",
     defaults: ["android-non-updatable_defaults_stubs_current"],
-    srcs: [ ":system-api-stubs-docs-non-updatable" ],
+    srcs: [":system-api-stubs-docs-non-updatable"],
     libs: modules_system_stubs,
     dist: {
         dir: "apistubs/android/system",
@@ -374,7 +399,10 @@
 java_defaults {
     name: "android_stubs_dists_default",
     dist: {
-        targets: ["sdk", "win_sdk"],
+        targets: [
+            "sdk",
+            "win_sdk",
+        ],
         tag: ".jar",
         dest: "android.jar",
     },
@@ -405,7 +433,10 @@
     dists: [
         {
             // Legacy dist path
-            targets: ["sdk", "win_sdk"],
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
             tag: ".jar",
             dest: "android_system.jar",
         },
@@ -427,14 +458,6 @@
     dist: {
         dir: "apistubs/android/test",
     },
-    dists: [
-        {
-            // Legacy dist path
-            targets: ["sdk", "win_sdk"],
-            tag: ".jar",
-            dest: "android_test.jar",
-        },
-    ],
 }
 
 java_library_static {
diff --git a/api/Android.bp b/api/Android.bp
index 485255f..6e83c08 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -308,6 +308,9 @@
 
 genrule {
     name: "combined-removed-dex",
+    visibility: [
+        "//frameworks/base/boot",
+    ],
     srcs: [
         ":frameworks-base-api-removed.txt",
         ":frameworks-base-api-system-removed.txt",
diff --git a/boot/Android.bp b/boot/Android.bp
index 71edea2..844dd64 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -43,4 +43,49 @@
 // done correctly.
 platform_bootclasspath {
     name: "platform-bootclasspath",
+
+    // Additional information needed by hidden api processing.
+    hidden_api: {
+        unsupported: [
+            "hiddenapi/hiddenapi-unsupported.txt",
+        ],
+        removed: [
+            ":combined-removed-dex",
+        ],
+        max_target_r_low_priority: [
+            "hiddenapi/hiddenapi-max-target-r-loprio.txt",
+        ],
+        max_target_q: [
+            "hiddenapi/hiddenapi-max-target-q.txt",
+        ],
+        max_target_p: [
+            "hiddenapi/hiddenapi-max-target-p.txt",
+        ],
+        max_target_o_low_priority: [
+            "hiddenapi/hiddenapi-max-target-o.txt",
+        ],
+        blocked: [
+            "hiddenapi/hiddenapi-force-blocked.txt",
+        ],
+        unsupported_packages: [
+            "hiddenapi/hiddenapi-unsupported-packages.txt",
+        ],
+    },
+
+    dists: [
+        {
+            targets: ["droidcore"],
+            tag: "hiddenapi-flags.csv",
+        },
+        {
+            targets: ["droidcore"],
+            tag: "hiddenapi-index.csv",
+        },
+        {
+            targets: ["droidcore"],
+            tag: "hiddenapi-metadata.csv",
+            // Legacy name
+            dest: "hiddenapi-unsupported.csv",
+        },
+    ],
 }
diff --git a/boot/hiddenapi/OWNERS b/boot/hiddenapi/OWNERS
index 5d869fc..74a3dc0 100644
--- a/boot/hiddenapi/OWNERS
+++ b/boot/hiddenapi/OWNERS
@@ -1,7 +1,5 @@
 # compat-team@ for changes to hiddenapi files
-andreionea@google.com
-mathewi@google.com
-satayev@google.com
+file:tools/platform-compat:/OWNERS
 
 # Escalations:
 per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
new file mode 100644
index 0000000..99c39f6
--- /dev/null
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -0,0 +1,392 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false
+#include "Log.h"
+
+#include "StatsPullerManager.h"
+
+#include <cutils/log.h>
+#include <math.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <iostream>
+
+#include "../StatsService.h"
+#include "../logd/LogEvent.h"
+#include "../stats_log_util.h"
+#include "../statscompanion_util.h"
+#include "StatsCallbackPuller.h"
+#include "TrainInfoPuller.h"
+#include "statslog_statsd.h"
+
+using std::shared_ptr;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Stores the puller as a wp to avoid holding a reference in case it is unregistered and
+// pullAtomCallbackDied is never called.
+struct PullAtomCallbackDeathCookie {
+    PullAtomCallbackDeathCookie(const wp<StatsPullerManager>& pullerManager,
+                                const PullerKey& pullerKey, const wp<StatsPuller>& puller) :
+            mPullerManager(pullerManager), mPullerKey(pullerKey), mPuller(puller) {
+    }
+
+    wp<StatsPullerManager> mPullerManager;
+    PullerKey mPullerKey;
+    wp<StatsPuller> mPuller;
+};
+
+void StatsPullerManager::pullAtomCallbackDied(void* cookie) {
+    PullAtomCallbackDeathCookie* cookie_ = static_cast<PullAtomCallbackDeathCookie*>(cookie);
+    sp<StatsPullerManager> thiz = cookie_->mPullerManager.promote();
+    if (!thiz) {
+        return;
+    }
+
+    const PullerKey& pullerKey = cookie_->mPullerKey;
+    wp<StatsPuller> puller = cookie_->mPuller;
+
+    // Erase the mapping from the puller key to the puller if the mapping still exists.
+    // Note that we are removing the StatsPuller object, which internally holds the binder
+    // IPullAtomCallback. However, each new registration creates a new StatsPuller, so this works.
+    lock_guard<mutex> lock(thiz->mLock);
+    const auto& it = thiz->kAllPullAtomInfo.find(pullerKey);
+    if (it != thiz->kAllPullAtomInfo.end() && puller != nullptr && puller == it->second) {
+        StatsdStats::getInstance().notePullerCallbackRegistrationChanged(pullerKey.atomTag,
+                                                                         /*registered=*/false);
+        thiz->kAllPullAtomInfo.erase(pullerKey);
+    }
+    // The death recipient corresponding to this specific IPullAtomCallback can never
+    // be triggered again, so free up resources.
+    delete cookie_;
+}
+
+// Values smaller than this may require to update the alarm.
+const int64_t NO_ALARM_UPDATE = INT64_MAX;
+
+StatsPullerManager::StatsPullerManager()
+    : kAllPullAtomInfo({
+              // TrainInfo.
+              {{.atomTag = util::TRAIN_INFO, .uid = AID_STATSD}, new TrainInfoPuller()},
+      }),
+      mNextPullTimeNs(NO_ALARM_UPDATE),
+      mPullAtomCallbackDeathRecipient(AIBinder_DeathRecipient_new(pullAtomCallbackDied)) {
+}
+
+bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
+                              vector<shared_ptr<LogEvent>>* data, bool useUids) {
+    std::lock_guard<std::mutex> _l(mLock);
+    return PullLocked(tagId, configKey, eventTimeNs, data, useUids);
+}
+
+bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
+                              vector<std::shared_ptr<LogEvent>>* data, bool useUids) {
+    std::lock_guard<std::mutex> _l(mLock);
+    return PullLocked(tagId, uids, eventTimeNs, data, useUids);
+}
+
+bool StatsPullerManager::PullLocked(int tagId, const ConfigKey& configKey,
+                                    const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data,
+                                    bool useUids) {
+    vector<int32_t> uids;
+    if (useUids) {
+        auto uidProviderIt = mPullUidProviders.find(configKey);
+        if (uidProviderIt == mPullUidProviders.end()) {
+            ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId,
+                  configKey.ToString().c_str());
+            StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
+            return false;
+        }
+        sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote();
+        if (pullUidProvider == nullptr) {
+            ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId,
+                  configKey.ToString().c_str());
+            StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
+            return false;
+        }
+        uids = pullUidProvider->getPullAtomUids(tagId);
+    }
+    return PullLocked(tagId, uids, eventTimeNs, data, useUids);
+}
+
+bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids,
+                                    const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data,
+                                    bool useUids) {
+    VLOG("Initiating pulling %d", tagId);
+    if (useUids) {
+        for (int32_t uid : uids) {
+            PullerKey key = {.atomTag = tagId, .uid = uid};
+            auto pullerIt = kAllPullAtomInfo.find(key);
+            if (pullerIt != kAllPullAtomInfo.end()) {
+                bool ret = pullerIt->second->Pull(eventTimeNs, data);
+                VLOG("pulled %zu items", data->size());
+                if (!ret) {
+                    StatsdStats::getInstance().notePullFailed(tagId);
+                }
+                return ret;
+            }
+        }
+        StatsdStats::getInstance().notePullerNotFound(tagId);
+        ALOGW("StatsPullerManager: Unknown tagId %d", tagId);
+        return false;  // Return early since we don't know what to pull.
+    } else {
+        PullerKey key = {.atomTag = tagId, .uid = -1};
+        auto pullerIt = kAllPullAtomInfo.find(key);
+        if (pullerIt != kAllPullAtomInfo.end()) {
+            bool ret = pullerIt->second->Pull(eventTimeNs, data);
+            VLOG("pulled %zu items", data->size());
+            if (!ret) {
+                StatsdStats::getInstance().notePullFailed(tagId);
+            }
+            return ret;
+        }
+        ALOGW("StatsPullerManager: Unknown tagId %d", tagId);
+        return false;  // Return early since we don't know what to pull.
+    }
+}
+
+bool StatsPullerManager::PullerForMatcherExists(int tagId) const {
+    // Pulled atoms might be registered after we parse the config, so just make sure the id is in
+    // an appropriate range.
+    return isVendorPulledAtom(tagId) || isPulledAtom(tagId);
+}
+
+void StatsPullerManager::updateAlarmLocked() {
+    if (mNextPullTimeNs == NO_ALARM_UPDATE) {
+        VLOG("No need to set alarms. Skipping");
+        return;
+    }
+
+    // TODO(b/151045771): do not hold a lock while making a binder call
+    if (mStatsCompanionService != nullptr) {
+        mStatsCompanionService->setPullingAlarm(mNextPullTimeNs / 1000000);
+    } else {
+        VLOG("StatsCompanionService not available. Alarm not set.");
+    }
+    return;
+}
+
+void StatsPullerManager::SetStatsCompanionService(
+        shared_ptr<IStatsCompanionService> statsCompanionService) {
+    std::lock_guard<std::mutex> _l(mLock);
+    shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
+    mStatsCompanionService = statsCompanionService;
+    for (const auto& pulledAtom : kAllPullAtomInfo) {
+        pulledAtom.second->SetStatsCompanionService(statsCompanionService);
+    }
+    if (mStatsCompanionService != nullptr) {
+        updateAlarmLocked();
+    }
+}
+
+void StatsPullerManager::RegisterReceiver(int tagId, const ConfigKey& configKey,
+                                          wp<PullDataReceiver> receiver, int64_t nextPullTimeNs,
+                                          int64_t intervalNs) {
+    std::lock_guard<std::mutex> _l(mLock);
+    auto& receivers = mReceivers[{.atomTag = tagId, .configKey = configKey}];
+    for (auto it = receivers.begin(); it != receivers.end(); it++) {
+        if (it->receiver == receiver) {
+            VLOG("Receiver already registered of %d", (int)receivers.size());
+            return;
+        }
+    }
+    ReceiverInfo receiverInfo;
+    receiverInfo.receiver = receiver;
+
+    // Round it to the nearest minutes. This is the limit of alarm manager.
+    // In practice, we should always have larger buckets.
+    int64_t roundedIntervalNs = intervalNs / NS_PER_SEC / 60 * NS_PER_SEC * 60;
+    // Scheduled pulling should be at least 1 min apart.
+    // This can be lower in cts tests, in which case we round it to 1 min.
+    if (roundedIntervalNs < 60 * (int64_t)NS_PER_SEC) {
+        roundedIntervalNs = 60 * (int64_t)NS_PER_SEC;
+    }
+
+    receiverInfo.intervalNs = roundedIntervalNs;
+    receiverInfo.nextPullTimeNs = nextPullTimeNs;
+    receivers.push_back(receiverInfo);
+
+    // There is only one alarm for all pulled events. So only set it to the smallest denom.
+    if (nextPullTimeNs < mNextPullTimeNs) {
+        VLOG("Updating next pull time %lld", (long long)mNextPullTimeNs);
+        mNextPullTimeNs = nextPullTimeNs;
+        updateAlarmLocked();
+    }
+    VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
+}
+
+void StatsPullerManager::UnRegisterReceiver(int tagId, const ConfigKey& configKey,
+                                            wp<PullDataReceiver> receiver) {
+    std::lock_guard<std::mutex> _l(mLock);
+    auto receiversIt = mReceivers.find({.atomTag = tagId, .configKey = configKey});
+    if (receiversIt == mReceivers.end()) {
+        VLOG("Unknown pull code or no receivers: %d", tagId);
+        return;
+    }
+    std::list<ReceiverInfo>& receivers = receiversIt->second;
+    for (auto it = receivers.begin(); it != receivers.end(); it++) {
+        if (receiver == it->receiver) {
+            receivers.erase(it);
+            VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size());
+            return;
+        }
+    }
+}
+
+void StatsPullerManager::RegisterPullUidProvider(const ConfigKey& configKey,
+                                                 wp<PullUidProvider> provider) {
+    std::lock_guard<std::mutex> _l(mLock);
+    mPullUidProviders[configKey] = provider;
+}
+
+void StatsPullerManager::UnregisterPullUidProvider(const ConfigKey& configKey,
+                                                   wp<PullUidProvider> provider) {
+    std::lock_guard<std::mutex> _l(mLock);
+    const auto& it = mPullUidProviders.find(configKey);
+    if (it != mPullUidProviders.end() && it->second == provider) {
+        mPullUidProviders.erase(it);
+    }
+}
+
+void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) {
+    std::lock_guard<std::mutex> _l(mLock);
+    int64_t wallClockNs = getWallClockNs();
+
+    int64_t minNextPullTimeNs = NO_ALARM_UPDATE;
+
+    vector<pair<const ReceiverKey*, vector<ReceiverInfo*>>> needToPull;
+    for (auto& pair : mReceivers) {
+        vector<ReceiverInfo*> receivers;
+        if (pair.second.size() != 0) {
+            for (ReceiverInfo& receiverInfo : pair.second) {
+                if (receiverInfo.nextPullTimeNs <= elapsedTimeNs) {
+                    receivers.push_back(&receiverInfo);
+                } else {
+                    if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) {
+                        minNextPullTimeNs = receiverInfo.nextPullTimeNs;
+                    }
+                }
+            }
+            if (receivers.size() > 0) {
+                needToPull.push_back(make_pair(&pair.first, receivers));
+            }
+        }
+    }
+    for (const auto& pullInfo : needToPull) {
+        vector<shared_ptr<LogEvent>> data;
+        bool pullSuccess = PullLocked(pullInfo.first->atomTag, pullInfo.first->configKey,
+                                      elapsedTimeNs, &data);
+        if (!pullSuccess) {
+            VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
+        }
+
+        // Convention is to mark pull atom timestamp at request time.
+        // If we pull at t0, puller starts at t1, finishes at t2, and send back
+        // at t3, we mark t0 as its timestamp, which should correspond to its
+        // triggering event, such as condition change at t0.
+        // Here the triggering event is alarm fired from AlarmManager.
+        // In ValueMetricProducer and GaugeMetricProducer we do same thing
+        // when pull on condition change, etc.
+        for (auto& event : data) {
+            event->setElapsedTimestampNs(elapsedTimeNs);
+            event->setLogdWallClockTimestampNs(wallClockNs);
+        }
+
+        for (const auto& receiverInfo : pullInfo.second) {
+            sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
+            if (receiverPtr != nullptr) {
+                receiverPtr->onDataPulled(data, pullSuccess, elapsedTimeNs);
+                // We may have just come out of a coma, compute next pull time.
+                int numBucketsAhead =
+                        (elapsedTimeNs - receiverInfo->nextPullTimeNs) / receiverInfo->intervalNs;
+                receiverInfo->nextPullTimeNs += (numBucketsAhead + 1) * receiverInfo->intervalNs;
+                if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
+                    minNextPullTimeNs = receiverInfo->nextPullTimeNs;
+                }
+            } else {
+                VLOG("receiver already gone.");
+            }
+        }
+    }
+
+    VLOG("mNextPullTimeNs: %lld updated to %lld", (long long)mNextPullTimeNs,
+         (long long)minNextPullTimeNs);
+    mNextPullTimeNs = minNextPullTimeNs;
+    updateAlarmLocked();
+}
+
+int StatsPullerManager::ForceClearPullerCache() {
+    std::lock_guard<std::mutex> _l(mLock);
+    int totalCleared = 0;
+    for (const auto& pulledAtom : kAllPullAtomInfo) {
+        totalCleared += pulledAtom.second->ForceClearCache();
+    }
+    return totalCleared;
+}
+
+int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) {
+    std::lock_guard<std::mutex> _l(mLock);
+    int totalCleared = 0;
+    for (const auto& pulledAtom : kAllPullAtomInfo) {
+        totalCleared += pulledAtom.second->ClearCacheIfNecessary(timestampNs);
+    }
+    return totalCleared;
+}
+
+void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t atomTag,
+                                                  const int64_t coolDownNs, const int64_t timeoutNs,
+                                                  const vector<int32_t>& additiveFields,
+                                                  const shared_ptr<IPullAtomCallback>& callback,
+                                                  bool useUid) {
+    std::lock_guard<std::mutex> _l(mLock);
+    VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
+
+    if (callback == nullptr) {
+        ALOGW("SetPullAtomCallback called with null callback for atom %d.", atomTag);
+        return;
+    }
+
+    StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
+    int64_t actualCoolDownNs = coolDownNs < kMinCoolDownNs ? kMinCoolDownNs : coolDownNs;
+    int64_t actualTimeoutNs = timeoutNs > kMaxTimeoutNs ? kMaxTimeoutNs : timeoutNs;
+
+    sp<StatsCallbackPuller> puller = new StatsCallbackPuller(atomTag, callback, actualCoolDownNs,
+                                                             actualTimeoutNs, additiveFields);
+    PullerKey key = {.atomTag = atomTag, .uid = useUid ? uid : -1};
+    AIBinder_linkToDeath(callback->asBinder().get(), mPullAtomCallbackDeathRecipient.get(),
+                         new PullAtomCallbackDeathCookie(this, key, puller));
+    kAllPullAtomInfo[key] = puller;
+}
+
+void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag,
+                                                    bool useUids) {
+    std::lock_guard<std::mutex> _l(mLock);
+    PullerKey key = {.atomTag = atomTag, .uid = useUids ? uid : -1};
+    if (kAllPullAtomInfo.find(key) != kAllPullAtomInfo.end()) {
+        StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag,
+                                                                         /*registered=*/false);
+        kAllPullAtomInfo.erase(key);
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
new file mode 100644
index 0000000..4f03172
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -0,0 +1,618 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false  // STOPSHIP if true
+#include "logd/LogEvent.h"
+
+#include <android-base/stringprintf.h>
+#include <android/binder_ibinder.h>
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
+#include "annotations.h"
+#include "stats_log_util.h"
+#include "statslog_statsd.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// for TrainInfo experiment id serialization
+const int FIELD_ID_EXPERIMENT_ID = 1;
+
+using namespace android::util;
+using android::base::StringPrintf;
+using android::util::ProtoOutputStream;
+using std::string;
+using std::vector;
+
+// stats_event.h socket types. Keep in sync.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+LogEvent::LogEvent(int32_t uid, int32_t pid)
+    : mLogdTimestampNs(time(nullptr)), mLogUid(uid), mLogPid(pid) {
+}
+
+LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
+                   bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
+                   const std::vector<uint8_t>& experimentIds, int32_t userId) {
+    mLogdTimestampNs = getWallClockNs();
+    mElapsedTimestampNs = getElapsedRealtimeNs();
+    mTagId = util::BINARY_PUSH_STATE_CHANGED;
+    mLogUid = AIBinder_getCallingUid();
+    mLogPid = AIBinder_getCallingPid();
+
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
+    mValues.push_back(
+            FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                   const InstallTrainInfo& trainInfo) {
+    mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
+    mTagId = util::TRAIN_INFO;
+
+    mValues.push_back(
+            FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
+    std::vector<uint8_t> experimentIdsProto;
+    writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto);
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
+}
+
+void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    int32_t value = readNextValue<int32_t>();
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    int64_t value = readNextValue<int64_t>();
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    int32_t numBytes = readNextValue<int32_t>();
+    if ((uint32_t)numBytes > mRemainingLen) {
+        mValid = false;
+        return;
+    }
+
+    string value = string((char*)mBuf, numBytes);
+    mBuf += numBytes;
+    mRemainingLen -= numBytes;
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    float value = readNextValue<float>();
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    // cast to int32_t because FieldValue does not support bools
+    int32_t value = (int32_t)readNextValue<uint8_t>();
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    int32_t numBytes = readNextValue<int32_t>();
+    if ((uint32_t)numBytes > mRemainingLen) {
+        mValid = false;
+        return;
+    }
+
+    vector<uint8_t> value(mBuf, mBuf + numBytes);
+    mBuf += numBytes;
+    mRemainingLen -= numBytes;
+    addToValues(pos, depth, value, last);
+    parseAnnotations(numAnnotations);
+}
+
+void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
+    int32_t numPairs = readNextValue<uint8_t>();
+
+    for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
+        last[1] = (pos[1] == numPairs);
+
+        // parse key
+        pos[2] = 1;
+        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+
+        // parse value
+        last[2] = true;
+
+        uint8_t typeInfo = readNextValue<uint8_t>();
+        switch (getTypeId(typeInfo)) {
+            case INT32_TYPE:
+                pos[2] = 2;  // pos[2] determined by index of type in KeyValuePair in atoms.proto
+                parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+                break;
+            case INT64_TYPE:
+                pos[2] = 3;
+                parseInt64(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+                break;
+            case STRING_TYPE:
+                pos[2] = 4;
+                parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+                break;
+            case FLOAT_TYPE:
+                pos[2] = 5;
+                parseFloat(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+                break;
+            default:
+                mValid = false;
+        }
+    }
+
+    parseAnnotations(numAnnotations);
+
+    pos[1] = pos[2] = 1;
+    last[1] = last[2] = false;
+}
+
+void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
+                                     uint8_t numAnnotations) {
+    const unsigned int firstUidInChainIndex = mValues.size();
+    const int32_t numNodes = readNextValue<uint8_t>();
+    for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
+        last[1] = (pos[1] == numNodes);
+
+        // parse uid
+        pos[2] = 1;
+        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+
+        // parse tag
+        pos[2] = 2;
+        last[2] = true;
+        parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
+    }
+
+    if (mValues.size() - 1 > INT8_MAX) {
+        mValid = false;
+    } else if (mValues.size() - 1 > firstUidInChainIndex) {
+        // At least one node was successfully parsed.
+        mAttributionChainStartIndex = static_cast<int8_t>(firstUidInChainIndex);
+        mAttributionChainEndIndex = static_cast<int8_t>(mValues.size() - 1);
+    }
+
+    if (mValid) {
+        parseAnnotations(numAnnotations, firstUidInChainIndex);
+    }
+
+    pos[1] = pos[2] = 1;
+    last[1] = last[2] = false;
+}
+
+// Assumes that mValues is not empty
+bool LogEvent::checkPreviousValueType(Type expected) {
+    return mValues[mValues.size() - 1].mValue.getType() == expected;
+}
+
+void LogEvent::parseIsUidAnnotation(uint8_t annotationType) {
+    if (mValues.empty() || mValues.size() - 1 > INT8_MAX || !checkPreviousValueType(INT)
+            || annotationType != BOOL_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    bool isUid = readNextValue<uint8_t>();
+    if (isUid) mUidFieldIndex = static_cast<int8_t>(mValues.size() - 1);
+    mValues[mValues.size() - 1].mAnnotations.setUidField(isUid);
+}
+
+void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
+    if (!mValues.empty() || annotationType != BOOL_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    mTruncateTimestamp = readNextValue<uint8_t>();
+}
+
+void LogEvent::parsePrimaryFieldAnnotation(uint8_t annotationType) {
+    if (mValues.empty() || annotationType != BOOL_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    const bool primaryField = readNextValue<uint8_t>();
+    mValues[mValues.size() - 1].mAnnotations.setPrimaryField(primaryField);
+}
+
+void LogEvent::parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,
+                                                   int firstUidInChainIndex) {
+    if (mValues.empty() || annotationType != BOOL_TYPE || -1 == firstUidInChainIndex) {
+        mValid = false;
+        return;
+    }
+
+    if (static_cast<int>(mValues.size() - 1) < firstUidInChainIndex) { // AttributionChain is empty.
+        mValid = false;
+        android_errorWriteLog(0x534e4554, "174485572");
+        return;
+    }
+
+    const bool primaryField = readNextValue<uint8_t>();
+    mValues[firstUidInChainIndex].mAnnotations.setPrimaryField(primaryField);
+}
+
+void LogEvent::parseExclusiveStateAnnotation(uint8_t annotationType) {
+    if (mValues.empty() || annotationType != BOOL_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    if (mValues.size() - 1 > INT8_MAX) {
+        android_errorWriteLog(0x534e4554, "174488848");
+        mValid = false;
+        return;
+    }
+
+    const bool exclusiveState = readNextValue<uint8_t>();
+    mExclusiveStateFieldIndex = static_cast<int8_t>(mValues.size() - 1);
+    mValues[getExclusiveStateFieldIndex()].mAnnotations.setExclusiveState(exclusiveState);
+}
+
+void LogEvent::parseTriggerStateResetAnnotation(uint8_t annotationType) {
+    if (mValues.empty() || annotationType != INT32_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    mResetState = readNextValue<int32_t>();
+}
+
+void LogEvent::parseStateNestedAnnotation(uint8_t annotationType) {
+    if (mValues.empty() || annotationType != BOOL_TYPE) {
+        mValid = false;
+        return;
+    }
+
+    bool nested = readNextValue<uint8_t>();
+    mValues[mValues.size() - 1].mAnnotations.setNested(nested);
+}
+
+// firstUidInChainIndex is a default parameter that is only needed when parsing
+// annotations for attribution chains.
+void LogEvent::parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex) {
+    for (uint8_t i = 0; i < numAnnotations; i++) {
+        uint8_t annotationId = readNextValue<uint8_t>();
+        uint8_t annotationType = readNextValue<uint8_t>();
+
+        switch (annotationId) {
+            case ANNOTATION_ID_IS_UID:
+                parseIsUidAnnotation(annotationType);
+                break;
+            case ANNOTATION_ID_TRUNCATE_TIMESTAMP:
+                parseTruncateTimestampAnnotation(annotationType);
+                break;
+            case ANNOTATION_ID_PRIMARY_FIELD:
+                parsePrimaryFieldAnnotation(annotationType);
+                break;
+            case ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID:
+                parsePrimaryFieldFirstUidAnnotation(annotationType, firstUidInChainIndex);
+                break;
+            case ANNOTATION_ID_EXCLUSIVE_STATE:
+                parseExclusiveStateAnnotation(annotationType);
+                break;
+            case ANNOTATION_ID_TRIGGER_STATE_RESET:
+                parseTriggerStateResetAnnotation(annotationType);
+                break;
+            case ANNOTATION_ID_STATE_NESTED:
+                parseStateNestedAnnotation(annotationType);
+                break;
+            default:
+                mValid = false;
+                return;
+        }
+    }
+}
+
+// This parsing logic is tied to the encoding scheme used in StatsEvent.java and
+// stats_event.c
+bool LogEvent::parseBuffer(uint8_t* buf, size_t len) {
+    mBuf = buf;
+    mRemainingLen = (uint32_t)len;
+
+    int32_t pos[] = {1, 1, 1};
+    bool last[] = {false, false, false};
+
+    // Beginning of buffer is OBJECT_TYPE | NUM_FIELDS | TIMESTAMP | ATOM_ID
+    uint8_t typeInfo = readNextValue<uint8_t>();
+    if (getTypeId(typeInfo) != OBJECT_TYPE) mValid = false;
+
+    uint8_t numElements = readNextValue<uint8_t>();
+    if (numElements < 2 || numElements > 127) mValid = false;
+
+    typeInfo = readNextValue<uint8_t>();
+    if (getTypeId(typeInfo) != INT64_TYPE) mValid = false;
+    mElapsedTimestampNs = readNextValue<int64_t>();
+    numElements--;
+
+    typeInfo = readNextValue<uint8_t>();
+    if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
+    mTagId = readNextValue<int32_t>();
+    numElements--;
+    parseAnnotations(getNumAnnotations(typeInfo));  // atom-level annotations
+
+    for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
+        last[0] = (pos[0] == numElements);
+
+        typeInfo = readNextValue<uint8_t>();
+        uint8_t typeId = getTypeId(typeInfo);
+
+        switch (typeId) {
+            case BOOL_TYPE:
+                parseBool(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case INT32_TYPE:
+                parseInt32(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case INT64_TYPE:
+                parseInt64(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case FLOAT_TYPE:
+                parseFloat(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case BYTE_ARRAY_TYPE:
+                parseByteArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case STRING_TYPE:
+                parseString(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case KEY_VALUE_PAIRS_TYPE:
+                parseKeyValuePairs(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case ATTRIBUTION_CHAIN_TYPE:
+                parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+                break;
+            case ERROR_TYPE:
+                /* mErrorBitmask =*/ readNextValue<int32_t>();
+                mValid = false;
+                break;
+            default:
+                mValid = false;
+                break;
+        }
+    }
+
+    if (mRemainingLen != 0) mValid = false;
+    mBuf = nullptr;
+    return mValid;
+}
+
+uint8_t LogEvent::getTypeId(uint8_t typeInfo) {
+    return typeInfo & 0x0F;  // type id in lower 4 bytes
+}
+
+uint8_t LogEvent::getNumAnnotations(uint8_t typeInfo) {
+    return (typeInfo >> 4) & 0x0F;  // num annotations in upper 4 bytes
+}
+
+int64_t LogEvent::GetLong(size_t key, status_t* err) const {
+    // TODO(b/110561208): encapsulate the magical operations in Field struct as static functions
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == LONG) {
+                return value.mValue.long_value;
+            } else if (value.mValue.getType() == INT) {
+                return value.mValue.int_value;
+            } else {
+                *err = BAD_TYPE;
+                return 0;
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return 0;
+}
+
+int LogEvent::GetInt(size_t key, status_t* err) const {
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == INT) {
+                return value.mValue.int_value;
+            } else {
+                *err = BAD_TYPE;
+                return 0;
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return 0;
+}
+
+const char* LogEvent::GetString(size_t key, status_t* err) const {
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == STRING) {
+                return value.mValue.str_value.c_str();
+            } else {
+                *err = BAD_TYPE;
+                return 0;
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return NULL;
+}
+
+bool LogEvent::GetBool(size_t key, status_t* err) const {
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == INT) {
+                return value.mValue.int_value != 0;
+            } else if (value.mValue.getType() == LONG) {
+                return value.mValue.long_value != 0;
+            } else {
+                *err = BAD_TYPE;
+                return false;
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return false;
+}
+
+float LogEvent::GetFloat(size_t key, status_t* err) const {
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == FLOAT) {
+                return value.mValue.float_value;
+            } else {
+                *err = BAD_TYPE;
+                return 0.0;
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return 0.0;
+}
+
+std::vector<uint8_t> LogEvent::GetStorage(size_t key, status_t* err) const {
+    int field = getSimpleField(key);
+    for (const auto& value : mValues) {
+        if (value.mField.getField() == field) {
+            if (value.mValue.getType() == STORAGE) {
+                return value.mValue.storage_value;
+            } else {
+                *err = BAD_TYPE;
+                return vector<uint8_t>();
+            }
+        }
+        if ((size_t)value.mField.getPosAtDepth(0) > key) {
+            break;
+        }
+    }
+
+    *err = BAD_INDEX;
+    return vector<uint8_t>();
+}
+
+string LogEvent::ToString() const {
+    string result;
+    result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs,
+                           (long long)mElapsedTimestampNs, mTagId);
+    for (const auto& value : mValues) {
+        result +=
+                StringPrintf("%#x", value.mField.getField()) + "->" + value.mValue.toString() + " ";
+    }
+    result += " }";
+    return result;
+}
+
+void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
+    writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
+}
+
+bool LogEvent::hasAttributionChain(std::pair<int, int>* indexRange) const {
+    if (mAttributionChainStartIndex == -1 || mAttributionChainEndIndex == -1) {
+        return false;
+    }
+
+    if (nullptr != indexRange) {
+        indexRange->first = static_cast<int>(mAttributionChainStartIndex);
+        indexRange->second = static_cast<int>(mAttributionChainEndIndex);
+    }
+
+    return true;
+}
+
+void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds,
+                               std::vector<uint8_t>* protoOut) {
+    ProtoOutputStream proto;
+    for (const auto& expId : experimentIds) {
+        proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+                    (long long)expId);
+    }
+
+    protoOut->resize(proto.size());
+    size_t pos = 0;
+    sp<ProtoReader> reader = proto.data();
+    while (reader->readBuffer() != NULL) {
+        size_t toRead = reader->currentToRead();
+        std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead);
+        pos += toRead;
+        reader->move(toRead);
+    }
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
new file mode 100644
index 0000000..aed2547
--- /dev/null
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -0,0 +1,481 @@
+// 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 "src/logd/LogEvent.h"
+
+#include <gtest/gtest.h>
+
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
+#include "log/log_event_list.h"
+#include "stats_event.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::string;
+using std::vector;
+using util::ProtoOutputStream;
+using util::ProtoReader;
+
+namespace {
+
+Field getField(int32_t tag, const vector<int32_t>& pos, int32_t depth, const vector<bool>& last) {
+    Field f(tag, (int32_t*)pos.data(), depth);
+
+    // For loop starts at 1 because the last field at depth 0 is not decorated.
+    for (int i = 1; i < depth; i++) {
+        if (last[i]) f.decorateLastPos(i);
+    }
+
+    return f;
+}
+
+void createIntWithBoolAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
+                                         bool annotationValue) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
+    AStatsEvent_writeInt32(statsEvent, 10);
+    AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    EXPECT_TRUE(logEvent->parseBuffer(buf, size));
+
+    AStatsEvent_release(statsEvent);
+}
+
+void createIntWithIntAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
+                                        int annotationValue) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
+    AStatsEvent_writeInt32(statsEvent, 10);
+    AStatsEvent_addInt32Annotation(statsEvent, annotationId, annotationValue);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    EXPECT_TRUE(logEvent->parseBuffer(buf, size));
+
+    AStatsEvent_release(statsEvent);
+}
+
+}  // anonymous namespace
+
+TEST(LogEventTest, TestPrimitiveParsing) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    AStatsEvent_writeInt32(event, 10);
+    AStatsEvent_writeInt64(event, 0x123456789);
+    AStatsEvent_writeFloat(event, 2.0);
+    AStatsEvent_writeBool(event, true);
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+
+    EXPECT_EQ(100, logEvent.GetTagId());
+    EXPECT_EQ(1000, logEvent.GetUid());
+    EXPECT_EQ(1001, logEvent.GetPid());
+    EXPECT_FALSE(logEvent.hasAttributionChain());
+
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(4, values.size());
+
+    const FieldValue& int32Item = values[0];
+    Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
+    EXPECT_EQ(expectedField, int32Item.mField);
+    EXPECT_EQ(Type::INT, int32Item.mValue.getType());
+    EXPECT_EQ(10, int32Item.mValue.int_value);
+
+    const FieldValue& int64Item = values[1];
+    expectedField = getField(100, {2, 1, 1}, 0, {false, false, false});
+    EXPECT_EQ(expectedField, int64Item.mField);
+    EXPECT_EQ(Type::LONG, int64Item.mValue.getType());
+    EXPECT_EQ(0x123456789, int64Item.mValue.long_value);
+
+    const FieldValue& floatItem = values[2];
+    expectedField = getField(100, {3, 1, 1}, 0, {false, false, false});
+    EXPECT_EQ(expectedField, floatItem.mField);
+    EXPECT_EQ(Type::FLOAT, floatItem.mValue.getType());
+    EXPECT_EQ(2.0, floatItem.mValue.float_value);
+
+    const FieldValue& boolItem = values[3];
+    expectedField = getField(100, {4, 1, 1}, 0, {true, false, false});
+    EXPECT_EQ(expectedField, boolItem.mField);
+    EXPECT_EQ(Type::INT, boolItem.mValue.getType());  // FieldValue does not support boolean type
+    EXPECT_EQ(1, boolItem.mValue.int_value);
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestStringAndByteArrayParsing) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    string str = "test";
+    AStatsEvent_writeString(event, str.c_str());
+    AStatsEvent_writeByteArray(event, (uint8_t*)str.c_str(), str.length());
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+
+    EXPECT_EQ(100, logEvent.GetTagId());
+    EXPECT_EQ(1000, logEvent.GetUid());
+    EXPECT_EQ(1001, logEvent.GetPid());
+    EXPECT_FALSE(logEvent.hasAttributionChain());
+
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(2, values.size());
+
+    const FieldValue& stringItem = values[0];
+    Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
+    EXPECT_EQ(expectedField, stringItem.mField);
+    EXPECT_EQ(Type::STRING, stringItem.mValue.getType());
+    EXPECT_EQ(str, stringItem.mValue.str_value);
+
+    const FieldValue& storageItem = values[1];
+    expectedField = getField(100, {2, 1, 1}, 0, {true, false, false});
+    EXPECT_EQ(expectedField, storageItem.mField);
+    EXPECT_EQ(Type::STORAGE, storageItem.mValue.getType());
+    vector<uint8_t> expectedValue = {'t', 'e', 's', 't'};
+    EXPECT_EQ(expectedValue, storageItem.mValue.storage_value);
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestEmptyString) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    string empty = "";
+    AStatsEvent_writeString(event, empty.c_str());
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+
+    EXPECT_EQ(100, logEvent.GetTagId());
+    EXPECT_EQ(1000, logEvent.GetUid());
+    EXPECT_EQ(1001, logEvent.GetPid());
+    EXPECT_FALSE(logEvent.hasAttributionChain());
+
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(1, values.size());
+
+    const FieldValue& item = values[0];
+    Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
+    EXPECT_EQ(expectedField, item.mField);
+    EXPECT_EQ(Type::STRING, item.mValue.getType());
+    EXPECT_EQ(empty, item.mValue.str_value);
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestByteArrayWithNullCharacter) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    uint8_t message[] = {'\t', 'e', '\0', 's', 't'};
+    AStatsEvent_writeByteArray(event, message, 5);
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+
+    EXPECT_EQ(100, logEvent.GetTagId());
+    EXPECT_EQ(1000, logEvent.GetUid());
+    EXPECT_EQ(1001, logEvent.GetPid());
+
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(1, values.size());
+
+    const FieldValue& item = values[0];
+    Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
+    EXPECT_EQ(expectedField, item.mField);
+    EXPECT_EQ(Type::STORAGE, item.mValue.getType());
+    vector<uint8_t> expectedValue(message, message + 5);
+    EXPECT_EQ(expectedValue, item.mValue.storage_value);
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestAttributionChain) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    string tag1 = "tag1";
+    string tag2 = "tag2";
+
+    uint32_t uids[] = {1001, 1002};
+    const char* tags[] = {tag1.c_str(), tag2.c_str()};
+
+    AStatsEvent_writeAttributionChain(event, uids, tags, 2);
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+
+    EXPECT_EQ(100, logEvent.GetTagId());
+    EXPECT_EQ(1000, logEvent.GetUid());
+    EXPECT_EQ(1001, logEvent.GetPid());
+
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(4, values.size());  // 2 per attribution node
+
+    std::pair<int, int> attrIndexRange;
+    EXPECT_TRUE(logEvent.hasAttributionChain(&attrIndexRange));
+    EXPECT_EQ(0, attrIndexRange.first);
+    EXPECT_EQ(3, attrIndexRange.second);
+
+    // Check first attribution node
+    const FieldValue& uid1Item = values[0];
+    Field expectedField = getField(100, {1, 1, 1}, 2, {true, false, false});
+    EXPECT_EQ(expectedField, uid1Item.mField);
+    EXPECT_EQ(Type::INT, uid1Item.mValue.getType());
+    EXPECT_EQ(1001, uid1Item.mValue.int_value);
+
+    const FieldValue& tag1Item = values[1];
+    expectedField = getField(100, {1, 1, 2}, 2, {true, false, true});
+    EXPECT_EQ(expectedField, tag1Item.mField);
+    EXPECT_EQ(Type::STRING, tag1Item.mValue.getType());
+    EXPECT_EQ(tag1, tag1Item.mValue.str_value);
+
+    // Check second attribution nodes
+    const FieldValue& uid2Item = values[2];
+    expectedField = getField(100, {1, 2, 1}, 2, {true, true, false});
+    EXPECT_EQ(expectedField, uid2Item.mField);
+    EXPECT_EQ(Type::INT, uid2Item.mValue.getType());
+    EXPECT_EQ(1002, uid2Item.mValue.int_value);
+
+    const FieldValue& tag2Item = values[3];
+    expectedField = getField(100, {1, 2, 2}, 2, {true, true, true});
+    EXPECT_EQ(expectedField, tag2Item.mField);
+    EXPECT_EQ(Type::STRING, tag2Item.mValue.getType());
+    EXPECT_EQ(tag2, tag2Item.mValue.str_value);
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestAnnotationIdIsUid) {
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
+
+    const vector<FieldValue>& values = event.getValues();
+    ASSERT_EQ(values.size(), 1);
+    EXPECT_EQ(event.getUidFieldIndex(), 0);
+}
+
+TEST(LogEventTest, TestAnnotationIdStateNested) {
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
+
+    const vector<FieldValue>& values = event.getValues();
+    ASSERT_EQ(values.size(), 1);
+    EXPECT_TRUE(values[0].mAnnotations.isNested());
+}
+
+TEST(LogEventTest, TestPrimaryFieldAnnotation) {
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_PRIMARY_FIELD, true);
+
+    const vector<FieldValue>& values = event.getValues();
+    ASSERT_EQ(values.size(), 1);
+    EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
+}
+
+TEST(LogEventTest, TestExclusiveStateAnnotation) {
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
+
+    const vector<FieldValue>& values = event.getValues();
+    ASSERT_EQ(values.size(), 1);
+    EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
+}
+
+TEST(LogEventTest, TestPrimaryFieldFirstUidAnnotation) {
+    // Event has 10 ints and then an attribution chain
+    int numInts = 10;
+    int firstUidInChainIndex = numInts;
+    string tag1 = "tag1";
+    string tag2 = "tag2";
+    uint32_t uids[] = {1001, 1002};
+    const char* tags[] = {tag1.c_str(), tag2.c_str()};
+
+    // Construct AStatsEvent
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, 100);
+    for (int i = 0; i < numInts; i++) {
+        AStatsEvent_writeInt32(statsEvent, 10);
+    }
+    AStatsEvent_writeAttributionChain(statsEvent, uids, tags, 2);
+    AStatsEvent_addBoolAnnotation(statsEvent, ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
+    AStatsEvent_build(statsEvent);
+
+    // Construct LogEvent
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    LogEvent logEvent(/*uid=*/0, /*pid=*/0);
+    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+    AStatsEvent_release(statsEvent);
+
+    // Check annotation
+    const vector<FieldValue>& values = logEvent.getValues();
+    ASSERT_EQ(values.size(), numInts + 4);
+    EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
+}
+
+TEST(LogEventTest, TestResetStateAnnotation) {
+    int32_t resetState = 10;
+    LogEvent event(/*uid=*/0, /*pid=*/0);
+    createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_TRIGGER_STATE_RESET, resetState);
+
+    const vector<FieldValue>& values = event.getValues();
+    ASSERT_EQ(values.size(), 1);
+    EXPECT_EQ(event.getResetState(), resetState);
+}
+
+TEST(LogEventTest, TestExclusiveStateAnnotationAfterTooManyFields) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    const unsigned int numAttributionNodes = 64;
+
+    uint32_t uids[numAttributionNodes];
+    const char* tags[numAttributionNodes];
+
+    for (unsigned int i = 1; i <= numAttributionNodes; i++) {
+        uids[i-1] = i;
+        tags[i-1] = std::to_string(i).c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
+    AStatsEvent_writeInt32(event, 1);
+    AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
+
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_FALSE(logEvent.parseBuffer(buf, size));
+    EXPECT_EQ(-1, logEvent.getExclusiveStateFieldIndex());
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestUidAnnotationAfterTooManyFields) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    const unsigned int numAttributionNodes = 64;
+
+    uint32_t uids[numAttributionNodes];
+    const char* tags[numAttributionNodes];
+
+    for (unsigned int i = 1; i <= numAttributionNodes; i++) {
+        uids[i-1] = i;
+        tags[i-1] = std::to_string(i).c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
+    AStatsEvent_writeInt32(event, 1);
+    AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_IS_UID, true);
+
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_FALSE(logEvent.parseBuffer(buf, size));
+    EXPECT_EQ(-1, logEvent.getUidFieldIndex());
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestAttributionChainEndIndexAfterTooManyFields) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    const unsigned int numAttributionNodes = 65;
+
+    uint32_t uids[numAttributionNodes];
+    const char* tags[numAttributionNodes];
+
+    for (unsigned int i = 1; i <= numAttributionNodes; i++) {
+        uids[i-1] = i;
+        tags[i-1] = std::to_string(i).c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
+
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_FALSE(logEvent.parseBuffer(buf, size));
+    EXPECT_FALSE(logEvent.hasAttributionChain());
+
+    AStatsEvent_release(event);
+}
+
+TEST(LogEventTest, TestEmptyAttributionChainWithPrimaryFieldFirstUidAnnotation) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    uint32_t uids[] = {};
+    const char* tags[] = {};
+
+    AStatsEvent_writeInt32(event, 10);
+    AStatsEvent_writeAttributionChain(event, uids, tags, 0);
+    AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
+
+    AStatsEvent_build(event);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
+
+    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
+    EXPECT_FALSE(logEvent.parseBuffer(buf, size));
+
+    AStatsEvent_release(event);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c18a9e3..1102a0d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1480,6 +1480,7 @@
     method public boolean disableBLE();
     method public boolean enableBLE();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
@@ -1491,12 +1492,18 @@
     field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
     field public static final int ACTIVE_DEVICE_AUDIO = 0; // 0x0
     field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
+    field public static final int OOB_ERROR_ADAPTER_DISABLED = 2; // 0x2
+    field public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1; // 0x1
+    field public static final int OOB_ERROR_UNKNOWN = 0; // 0x0
   }
 
   public static interface BluetoothAdapter.OnMetadataChangedListener {
     method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
   }
 
+  public static interface BluetoothAdapter.OobDataCallback {
+  }
+
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
@@ -7307,7 +7314,7 @@
     method @NonNull public static String formatUid(int);
     method public static int getAppId(int);
     method public int getIdentifier();
-    method public static int getUid(@NonNull android.os.UserHandle, int);
+    method public int getUid(int);
     method @Deprecated public boolean isOwner();
     method public boolean isSystem();
     method public static int myUserId();
@@ -11997,7 +12004,6 @@
     method public int describeContents();
     method @Nullable public String getCallIdParameter();
     method @NonNull public byte[] getContent();
-    method @Deprecated @NonNull public byte[] getEncodedMessage();
     method @NonNull public String getHeaderSection();
     method @NonNull public String getStartLine();
     method @NonNull public String getViaBranchParameter();
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 919f1e2..965665d 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -127,3 +127,269 @@
     ],
     visibility: ["//frameworks/base/test-mock"],
 }
+
+filegroup {
+    name: "libincident_aidl",
+    srcs: [
+        "android/os/IIncidentDumpCallback.aidl",
+        "android/os/IIncidentManager.aidl",
+        "android/os/IIncidentReportStatusListener.aidl",
+    ],
+}
+
+filegroup {
+    name: "libvibrator_aidl",
+    srcs: [
+        "android/os/IExternalVibrationController.aidl",
+        "android/os/IExternalVibratorService.aidl",
+    ],
+}
+
+filegroup {
+    name: "libpowermanager_aidl",
+    srcs: [
+        "android/os/Temperature.aidl",
+        "android/os/CoolingDevice.aidl",
+        "android/os/IThermalEventListener.aidl",
+        "android/os/IThermalStatusListener.aidl",
+        "android/os/IThermalService.aidl",
+    ],
+}
+
+genrule {
+    name: "statslog-framework-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
+        " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
+    out: ["com/android/internal/util/FrameworkStatsLog.java"],
+}
+
+java_library {
+    name: "uieventloggerlib",
+    srcs: [
+        "com/android/internal/logging/UiEvent.java",
+        "com/android/internal/logging/UiEventLogger.java",
+        "com/android/internal/logging/UiEventLoggerImpl.java",
+        "com/android/internal/logging/InstanceId.java",
+        "com/android/internal/logging/InstanceIdSequence.java",
+        ":statslog-framework-java-gen",
+    ],
+}
+
+filegroup {
+    name: "framework-services-net-module-wifi-shared-srcs",
+    srcs: [
+        "android/net/DhcpResults.java",
+        "android/util/LocalLog.java",
+    ],
+}
+
+// keep these files in sync with the package/Tethering/jarjar-rules.txt and
+// package/Connectivity/jarjar-rules.txt for the tethering module and connectivity module.
+filegroup {
+    name: "framework-connectivity-shared-srcs",
+    srcs: [
+        "android/util/LocalLog.java",
+        // This should be android.util.IndentingPrintWriter, but it's not available in all branches.
+        "com/android/internal/util/IndentingPrintWriter.java",
+        "com/android/internal/util/IState.java",
+        "com/android/internal/util/MessageUtils.java",
+        "com/android/internal/util/State.java",
+        "com/android/internal/util/StateMachine.java",
+        "com/android/internal/util/WakeupMessage.java",
+    ],
+}
+
+filegroup {
+    name: "incremental_aidl",
+    srcs: [
+        "android/os/incremental/IIncrementalServiceConnector.aidl",
+        "android/os/incremental/IncrementalFileSystemControlParcel.aidl",
+    ],
+}
+
+filegroup {
+    name: "dataloader_aidl",
+    srcs: [
+        "android/content/pm/DataLoaderParamsParcel.aidl",
+        "android/content/pm/DataLoaderType.aidl",
+        "android/content/pm/FileSystemControlParcel.aidl",
+        "android/content/pm/IDataLoader.aidl",
+        "android/content/pm/IDataLoaderManager.aidl",
+        "android/content/pm/InstallationFileParcel.aidl",
+        "android/content/pm/InstallationFileLocation.aidl",
+        "android/content/pm/IDataLoaderStatusListener.aidl",
+        "android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
+    ],
+}
+
+filegroup {
+    name: "incremental_manager_aidl",
+    srcs: [
+        "android/os/incremental/IIncrementalService.aidl",
+        "android/os/incremental/IncrementalNewFileParams.aidl",
+        "android/os/incremental/IStorageHealthListener.aidl",
+        "android/os/incremental/StorageHealthCheckParams.aidl",
+    ],
+}
+
+filegroup {
+    name: "activity_manager_procstate_aidl",
+    srcs: [
+        // internal only
+    ],
+}
+
+aidl_interface {
+    name: "libincremental_aidl",
+    unstable: true,
+    srcs: [
+        ":incremental_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+        },
+    },
+}
+
+aidl_interface {
+    name: "libdataloader_aidl",
+    unstable: true,
+    srcs: [
+        ":dataloader_aidl",
+    ],
+    imports: [
+        "libincremental_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: false,
+        },
+    },
+}
+
+aidl_interface {
+    name: "libincremental_manager_aidl",
+    unstable: true,
+    srcs: [
+        ":incremental_manager_aidl",
+    ],
+    imports: [
+        "libincremental_aidl",
+        "libdataloader_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: false,
+        },
+    },
+}
+
+// Build Rust bindings for PermissionController. Needed by keystore2.
+aidl_interface {
+    name: "android.os.permissions_aidl",
+    unstable: true,
+    local_include_dir: ".",
+    srcs: [
+        "android/os/IPermissionController.aidl",
+    ],
+    backend: {
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+// Avoid including Parcelable classes as we don't want to have two copies of
+// Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
+// and TeleService app (packages/services/Telephony).
+filegroup {
+    name: "framework-telephony-common-shared-srcs",
+    srcs: [
+        "android/os/RegistrantList.java",
+        "android/os/Registrant.java",
+        "android/util/LocalLog.java",
+        "android/util/TimeUtils.java",
+        "com/android/internal/os/SomeArgs.java",
+        "com/android/internal/util/AsyncChannel.java",
+        "com/android/internal/util/AsyncService.java",
+        "com/android/internal/util/BitwiseInputStream.java",
+        "com/android/internal/util/FastXmlSerializer.java",
+        "com/android/internal/util/HexDump.java",
+        "com/android/internal/util/IState.java",
+        "com/android/internal/util/IndentingPrintWriter.java",
+        "com/android/internal/util/Preconditions.java",
+        "com/android/internal/util/State.java",
+        "com/android/internal/util/StateMachine.java",
+        "com/android/internal/util/UserIcons.java",
+    ],
+}
+
+// Avoid including Parcelable classes as we don't want to have two copies of
+// Parcelable cross the process.
+filegroup {
+    name: "framework-cellbroadcast-shared-srcs",
+    srcs: [
+        "android/os/HandlerExecutor.java",
+        "android/util/LocalLog.java",
+        "com/android/internal/util/IState.java",
+        "com/android/internal/util/Preconditions.java",
+        "com/android/internal/util/State.java",
+        "com/android/internal/util/StateMachine.java",
+    ],
+}
+
+filegroup {
+    name: "framework-ims-common-shared-srcs",
+    srcs: [
+        "android/os/RegistrantList.java",
+        "android/os/Registrant.java",
+        "com/android/internal/os/SomeArgs.java",
+        "com/android/internal/util/Preconditions.java",
+    ],
+}
+
+filegroup {
+    name: "framework-wifi-util-lib-aidls",
+    srcs: ["android/content/pm/ParceledListSlice.aidl"],
+}
+
+// utility classes statically linked into wifi-service
+filegroup {
+    name: "framework-wifi-service-shared-srcs",
+    srcs: [
+        "android/net/InterfaceConfiguration.java",
+        "android/util/BackupUtils.java",
+        "android/util/Rational.java",
+        "com/android/internal/util/FastXmlSerializer.java",
+        "com/android/internal/util/HexDump.java",
+        "com/android/internal/util/IState.java",
+        "com/android/internal/util/MessageUtils.java",
+        "com/android/internal/util/State.java",
+        "com/android/internal/util/StateMachine.java",
+        "com/android/internal/util/WakeupMessage.java",
+    ],
+    visibility: [
+        "//frameworks/opt/net/wifi/service",
+        "//packages/modules/Wifi/service",
+    ],
+}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 694c519..c4cdbbc 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7636,8 +7636,8 @@
                 } else if (collectionMode == COLLECT_SYNC
                         // Only collect app-ops when the proxy is trusted
                         && (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
-                        myUid) == PackageManager.PERMISSION_GRANTED
-                        || isTrustedVoiceServiceProxy(mContext, mContext.getOpPackageName(), op))) {
+                        myUid) == PackageManager.PERMISSION_GRANTED || isTrustedVoiceServiceProxy(
+                        mContext, mContext.getOpPackageName(), op, mContext.getUserId()))) {
                     collectNotedOpSync(op, proxiedAttributionTag);
                 }
             }
@@ -7655,7 +7655,7 @@
      * @hide
      */
     public static boolean isTrustedVoiceServiceProxy(Context context, String packageName,
-            int code) {
+            int code, int userId) {
         // This is a workaround for R QPR, new API change is not allowed. We only allow the current
         // voice recognizer is also the voice interactor to noteproxy op.
         if (code != OP_RECORD_AUDIO) {
@@ -7667,7 +7667,7 @@
         final String voiceRecognitionServicePackageName =
                 getComponentPackageNameFromString(voiceRecognitionComponent);
         return (Objects.equals(packageName, voiceRecognitionServicePackageName))
-                && isPackagePreInstalled(context, packageName);
+                && isPackagePreInstalled(context, packageName, userId);
     }
 
     private static String getComponentPackageNameFromString(String from) {
@@ -7675,10 +7675,10 @@
         return componentName != null ? componentName.getPackageName() : "";
     }
 
-    private static boolean isPackagePreInstalled(Context context, String packageName) {
+    private static boolean isPackagePreInstalled(Context context, String packageName, int userId) {
         try {
             final PackageManager pm = context.getPackageManager();
-            final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+            final ApplicationInfo info = pm.getApplicationInfoAsUser(packageName, 0, userId);
             return ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
         } catch (PackageManager.NameNotFoundException e) {
             return false;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 38863c2..7d62327 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -28,6 +28,7 @@
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.app.PropertyInvalidatedCache;
+import android.bluetooth.BluetoothDevice.Transport;
 import android.bluetooth.BluetoothProfile.ConnectionPolicy;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
@@ -3013,6 +3014,168 @@
         return false;
     }
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "OOB_ERROR_" }, value = {
+        OOB_ERROR_UNKNOWN,
+        OOB_ERROR_ANOTHER_ACTIVE_REQUEST,
+        OOB_ERROR_ADAPTER_DISABLED
+    })
+    public @interface OobError {}
+
+    /**
+     * An unknown error has occurred in the controller, stack, or callback pipeline.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int OOB_ERROR_UNKNOWN = 0;
+
+    /**
+     * If another application has already requested {@link OobData} then another fetch will be
+     * disallowed until the callback is removed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1;
+
+    /**
+     * The adapter is currently disabled, please enable it.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int OOB_ERROR_ADAPTER_DISABLED = 2;
+
+    /**
+     * Provides callback methods for receiving {@link OobData} from the host stack, as well as an
+     * error interface in order to allow the caller to determine next steps based on the {@link
+     * ErrorCode}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface OobDataCallback {
+        /**
+         * Handles the {@link OobData} received from the host stack.
+         *
+         * @param transport - whether the {@link OobData} is generated for LE or Classic.
+         * @param oobData - data generated in the host stack(LE) or controller (Classic)
+         *
+         * @hide
+         */
+        void onOobData(@Transport int transport, @Nullable OobData oobData);
+
+        /**
+         * Provides feedback when things don't go as expected.
+         *
+         * @param errorCode - the code descibing the type of error that occurred.
+         *
+         * @hide
+         */
+        void onError(@OobError int errorCode);
+    }
+
+    /**
+     * Wraps an AIDL interface around an {@link OobDataCallback} interface.
+     *
+     * @see {@link IBluetoothOobDataCallback} for interface definition.
+     *
+     * @hide
+     */
+    public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub {
+        private final OobDataCallback mCallback;
+        private final Executor mExecutor;
+
+        /**
+         * @param callback - object to receive {@link OobData} must be a non null argument
+         *
+         * @throws NullPointerException if the callback is null.
+         */
+        WrappedOobDataCallback(@NonNull OobDataCallback callback,
+                @NonNull @CallbackExecutor Executor executor) {
+            Preconditions.checkNotNull(callback);
+            Preconditions.checkNotNull(executor);
+            mCallback = callback;
+            mExecutor = executor;
+        }
+        /**
+         * Wrapper function to relay to the {@link OobDataCallback#onOobData}
+         *
+         * @param transport - whether the {@link OobData} is generated for LE or Classic.
+         * @param oobData - data generated in the host stack(LE) or controller (Classic)
+         *
+         * @hide
+         */
+        public void onOobData(@Transport int transport, OobData oobData) {
+            mExecutor.execute(new Runnable() {
+                public void run() {
+                    mCallback.onOobData(transport, oobData);
+                }
+            });
+        }
+        /**
+         * Wrapper function to relay to the {@link OobDataCallback#onError}
+         *
+         * @param errorCode - the code descibing the type of error that occurred.
+         *
+         * @hide
+         */
+        public void onError(@OobError int errorCode) {
+            mExecutor.execute(new Runnable() {
+                public void run() {
+                    mCallback.onError(errorCode);
+                }
+            });
+        }
+    }
+
+    /**
+     * Fetches a secret data value that can be used for a secure and simple pairing experience.
+     *
+     * <p>This is the Local Out of Band data the comes from the
+     *
+     * <p>This secret is the local Out of Band data.  This data is used to securely and quickly
+     * pair two devices with minimal user interaction.
+     *
+     * <p>For example, this secret can be transferred to a remote device out of band (meaning any
+     * other way besides using bluetooth).  Once the remote device finds this device using the
+     * information given in the data, such as the PUBLIC ADDRESS, the remote device could then
+     * connect to this device using this secret when the pairing sequenece asks for the secret.
+     * This device will respond by automatically accepting the pairing due to the secret being so
+     * trustworthy.
+     *
+     * @param transport - provide type of transport (e.g. LE or Classic).
+     * @param callback - target object to receive the {@link OobData} value.
+     *
+     * @throws NullPointerException if callback is null.
+     * @throws IllegalArgumentException if the transport is not valid.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void generateLocalOobData(@Transport int transport,
+            @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) {
+        if (transport != BluetoothDevice.TRANSPORT_BREDR && transport
+                != BluetoothDevice.TRANSPORT_LE) {
+            throw new IllegalArgumentException("Invalid transport '" + transport + "'!");
+        }
+        Preconditions.checkNotNull(callback);
+        if (!isEnabled()) {
+            Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!");
+            callback.onError(OOB_ERROR_ADAPTER_DISABLED);
+        } else {
+            try {
+                mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback,
+                        executor));
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+        }
+    }
+
     /**
      * Enable control of the Bluetooth Adapter for a single application.
      *
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c30b8af..a40bf34 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -931,6 +931,21 @@
     @SystemApi
     public static final int ACCESS_REJECTED = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+        prefix = { "TRANSPORT_" },
+        value = {
+            /** Allow host to automatically select a transport (dual-mode only) */
+            TRANSPORT_AUTO,
+            /** Use Classic or BR/EDR transport.*/
+            TRANSPORT_BREDR,
+            /** Use Low Energy transport.*/
+            TRANSPORT_LE,
+        }
+    )
+    public @interface Transport {}
+
     /**
      * No preference of physical transport for GATT connections to remote dual-mode devices
      */
@@ -1063,6 +1078,10 @@
         public void onBrEdrDown() {
             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
         }
+
+        public void onOobData(@Transport int transport, OobData oobData) {
+            if (DBG) Log.d(TAG, "onOobData: got data");
+        }
     };
 
     /**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index a42448c..b474d7c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -169,8 +169,9 @@
     public @interface ResumeOnRebootRebootErrorCode {}
 
     /**
-     * The preparation of resume on reboot succeeds. Don't expose it because a successful reboot
-     * should just reboot the device.
+     * The preparation of resume on reboot succeeds.
+     *
+     * <p> Don't expose it because a successful reboot should just reboot the device.
      *  @hide
      */
     public static final int RESUME_ON_REBOOT_REBOOT_ERROR_NONE = 0;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 7b62e66..d065d7a 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -303,16 +303,15 @@
     }
 
     /**
-     * Returns the uid that is composed from the userHandle and the appId.
+     * Returns the uid representing the given appId for this UserHandle.
      *
-     * @param userHandle the UserHandle to compose the uid
      * @param appId the AppId to compose the uid
-     * @return the uid that is composed from the userHandle and the appId
+     * @return the uid representing the given appId for this UserHandle
      * @hide
      */
     @SystemApi
-    public static int getUid(@NonNull UserHandle userHandle, @AppIdInt int appId) {
-        return getUid(userHandle.getIdentifier(), appId);
+    public int getUid(@AppIdInt int appId) {
+        return getUid(getIdentifier(), appId);
     }
 
     /**
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index a23fc4b..7ee846e 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -1,12 +1,15 @@
 package com.android.internal.util;
 
+import static android.content.Intent.ACTION_USER_SWITCHED;
 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -161,8 +164,21 @@
     private ServiceConnection mScreenshotConnection = null;
     private final Context mContext;
 
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mScreenshotLock) {
+                if (ACTION_USER_SWITCHED.equals(intent.getAction())) {
+                    resetConnection();
+                }
+            }
+        }
+    };
+
     public ScreenshotHelper(Context context) {
         mContext = context;
+        IntentFilter filter = new IntentFilter(ACTION_USER_SWITCHED);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
     }
 
     /**
@@ -279,9 +295,8 @@
             final Runnable mScreenshotTimeout = () -> {
                 synchronized (mScreenshotLock) {
                     if (mScreenshotConnection != null) {
-                        mContext.unbindService(mScreenshotConnection);
-                        mScreenshotConnection = null;
-                        mScreenshotService = null;
+                        Log.e(TAG, "Timed out before getting screenshot capture response");
+                        resetConnection();
                         notifyScreenshotError();
                     }
                 }
@@ -304,11 +319,7 @@
                             break;
                         case SCREENSHOT_MSG_PROCESS_COMPLETE:
                             synchronized (mScreenshotLock) {
-                                if (mScreenshotConnection != null) {
-                                    mContext.unbindService(mScreenshotConnection);
-                                    mScreenshotConnection = null;
-                                    mScreenshotService = null;
-                                }
+                                resetConnection();
                             }
                             break;
                     }
@@ -348,9 +359,7 @@
                     public void onServiceDisconnected(ComponentName name) {
                         synchronized (mScreenshotLock) {
                             if (mScreenshotConnection != null) {
-                                mContext.unbindService(mScreenshotConnection);
-                                mScreenshotConnection = null;
-                                mScreenshotService = null;
+                                resetConnection();
                                 // only log an error if we're still within the timeout period
                                 if (handler.hasCallbacks(mScreenshotTimeout)) {
                                     handler.removeCallbacks(mScreenshotTimeout);
@@ -383,6 +392,17 @@
     }
 
     /**
+     * Unbinds the current screenshot connection (if any).
+     */
+    private void resetConnection() {
+        if (mScreenshotConnection != null) {
+            mContext.unbindService(mScreenshotConnection);
+            mScreenshotConnection = null;
+            mScreenshotService = null;
+        }
+    }
+
+    /**
      * Notifies the screenshot service to show an error.
      */
     private void notifyScreenshotError() {
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index f5df3ab..940979d 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -16,15 +16,41 @@
 
 package com.android.internal.widget;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.admin.PasswordMetrics;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 /**
  * LockSettingsService local system service interface.
  *
  * @hide Only for use within the system server.
  */
 public abstract class LockSettingsInternal {
+    /** ErrorCode for armRebootEscrow failures. **/
+    @IntDef(prefix = {"ARM_REBOOT_ERROR_"}, value = {
+            ARM_REBOOT_ERROR_NONE,
+            ARM_REBOOT_ERROR_UNSPECIFIED,
+            ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+            ARM_REBOOT_ERROR_NO_PROVIDER,
+            ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+            ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+            ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+            ARM_REBOOT_ERROR_STORE_ESCROW_KEY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ArmRebootEscrowErrorCode {}
+
+    public static final int ARM_REBOOT_ERROR_NONE = 0;
+    public static final int ARM_REBOOT_ERROR_UNSPECIFIED = 1;
+    public static final int ARM_REBOOT_ERROR_ESCROW_NOT_READY = 2;
+    public static final int ARM_REBOOT_ERROR_NO_PROVIDER = 3;
+    public static final int ARM_REBOOT_ERROR_PROVIDER_MISMATCH = 4;
+    public static final int ARM_REBOOT_ERROR_NO_ESCROW_KEY = 5;
+    public static final int ARM_REBOOT_ERROR_KEYSTORE_FAILURE = 6;
+    public static final int ARM_REBOOT_ERROR_STORE_ESCROW_KEY = 7;
+    // TODO(b/183140900) split store escrow key errors into detailed ones.
 
     /**
      * Create an escrow token for the current user, which can later be used to unlock FBE
@@ -104,9 +130,9 @@
      * Should be called immediately before rebooting for an update. This depends on {@link
      * #prepareRebootEscrow()} having been called and the escrow completing.
      *
-     * @return true if the arming worked
+     * @return ARM_ERROR_NONE if the arming worked
      */
-    public abstract boolean armRebootEscrow();
+    public abstract @ArmRebootEscrowErrorCode int armRebootEscrow();
 
 
     /**
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bfe7802..58eb93f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1834,7 +1834,7 @@
     <string name="config_systemGallery" translatable="false">com.android.gallery3d</string>
 
     <!-- The name of the package that will be allowed to change its components' label/icon. -->
-    <string name="config_overrideComponentUiPackage" translatable="false"></string>
+    <string name="config_overrideComponentUiPackage" translatable="false">com.android.stk</string>
 
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 5633236..54d0659 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -4607,6 +4607,25 @@
             return mType;
         }
 
+        @Override
+        public boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            if (!(o instanceof ParameterDescriptor)) {
+                return false;
+            }
+            ParameterDescriptor other = (ParameterDescriptor) o;
+            return this.mName.equals(other.mName) && this.mType == other.mType;
+        }
+
+        @Override
+        public int hashCode() {
+            return Arrays.asList(
+                    (Object) mName,
+                    (Object) Integer.valueOf(mType)).hashCode();
+        }
+
         private String mName;
         private @MediaFormat.Type int mType;
     }
@@ -4631,7 +4650,8 @@
     private native ParameterDescriptor native_getParameterDescriptor(@NonNull String name);
 
     /**
-     * Subscribe to vendor parameters, so that changes to these parameters generate
+     * Subscribe to vendor parameters, so that these parameters will be present in
+     * {@link #getOutputFormat} and changes to these parameters generate
      * output format change event.
      * <p>
      * Unrecognized parameter names or standard (non-vendor) parameter names will be ignored.
@@ -4660,8 +4680,9 @@
     private native void native_subscribeToVendorParameters(@NonNull List<String> names);
 
     /**
-     * Unsubscribe from vendor parameters, so that changes to these parameters
-     * no longer generate output format change event.
+     * Unsubscribe from vendor parameters, so that these parameters will not be present in
+     * {@link #getOutputFormat} and changes to these parameters no longer generate
+     * output format change event.
      * <p>
      * Unrecognized parameter names, standard (non-vendor) parameter names will be ignored.
      * {@link #reset} also resets the list of subscribed parameters.
@@ -4669,7 +4690,8 @@
      * <p>
      * This method can be called in any codec state except for released state. When called in
      * running state with newly unsubscribed parameters, it takes effect no later than the
-     * processing of the subsequently queued buffer.
+     * processing of the subsequently queued buffer. For the removed parameters, the codec will
+     * generate output format change event.
      * <p>
      * Note that any vendor parameters set in a {@link #configure} or
      * {@link #setParameters} call are automatically subscribed, and with this method
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 3976086e..49ef504 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -3258,7 +3258,7 @@
     if (descramblerSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+    sp<IFilter> iFilterSp = (filter == NULL) ? NULL : getFilter(env, filter)->getIFilter();
     Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
     return (jint) result;
 }
@@ -3269,7 +3269,7 @@
     if (descramblerSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+    sp<IFilter> iFilterSp = (filter == NULL) ? NULL : getFilter(env, filter)->getIFilter();
     Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
     return (jint) result;
 }
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index ea9b52c..e4e5b9f 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -31,6 +31,7 @@
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
     <uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
 
     <application
         android:allowClearUserData="true"
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
index e501e12..5ac059b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
@@ -17,6 +17,7 @@
 package com.android.companiondevicemanager;
 
 import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import static java.util.Objects.requireNonNull;
 
@@ -58,6 +59,8 @@
             Log.e(LOG_TAG, "About to show UI, but no devices to show");
         }
 
+        getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
         if (getService().mRequest.isSingleDevice()) {
             setContentView(R.layout.device_confirmation);
             final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
index bc67c74..bd33292 100644
--- a/packages/Connectivity/framework/src/android/net/UidRange.java
+++ b/packages/Connectivity/framework/src/android/net/UidRange.java
@@ -46,8 +46,8 @@
     /** Creates a UidRange for the specified user. */
     public static UidRange createForUser(UserHandle user) {
         final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1);
-        final int start = UserHandle.getUid(user, 0 /* appId */);
-        final int end = UserHandle.getUid(nextUser, 0) - 1;
+        final int start = user.getUid(0 /* appId */);
+        final int end = nextUser.getUid(0 /* appId */) - 1;
         return new UidRange(start, end);
     }
 
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index ba83a44..efd3363 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.NetworkCapabilities.RedactionType;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -45,7 +46,7 @@
     public final String sessionId;
 
     @Override
-    public long getApplicableRedactions() {
+    public @RedactionType long getApplicableRedactions() {
         return REDACT_FOR_NETWORK_SETTINGS;
     }
 
@@ -53,7 +54,7 @@
      * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
      */
     @NonNull
-    public VpnTransportInfo makeCopy(long redactions) {
+    public VpnTransportInfo makeCopy(@RedactionType long redactions) {
         return new VpnTransportInfo(type,
             ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
     }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index cb610fc..bcde584 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -89,7 +89,7 @@
                         return value == null || value.length() < MAX_LENGTH;
                     }
                 });
-        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.85f, 1.3f));
+        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.25f, 5.0f));
         VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 System.DISPLAY_COLOR_MODE,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2ceef73..efb3768 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -9804,7 +9804,7 @@
                     }
                     for (final UserHandle ui : users) {
                         // Add the rules for all users as this policy is device wide.
-                        uids.get(pref).add(UserHandle.getUid(ui, uid));
+                        uids.get(pref).add(ui.getUid(uid));
                     }
                 } catch (PackageManager.NameNotFoundException e) {
                     // Although this may seem like an error scenario, it is ok that uninstalled
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 6560824..5f6d9bd 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -82,7 +82,7 @@
     private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
     private static final int DEFAULT_MAX_FILES = 1000;
     private static final int DEFAULT_MAX_FILES_LOWRAM = 300;
-    private static final int DEFAULT_QUOTA_KB = 5 * 1024;
+    private static final int DEFAULT_QUOTA_KB = 10 * 1024;
     private static final int DEFAULT_QUOTA_PERCENT = 10;
     private static final int DEFAULT_RESERVE_PERCENT = 10;
     private static final int QUOTA_RESCAN_MILLIS = 5000;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index f2236d7..db8dc71 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3003,8 +3003,8 @@
 
         // This is a workaround for R QPR, new API change is not allowed. We only allow the current
         // voice recognizer is also the voice interactor to noteproxy op.
-        final boolean isTrustVoiceServiceProxy =
-                AppOpsManager.isTrustedVoiceServiceProxy(mContext, proxyPackageName, code);
+        final boolean isTrustVoiceServiceProxy = AppOpsManager.isTrustedVoiceServiceProxy(mContext,
+                proxyPackageName, code, UserHandle.getUserId(proxyUid));
         final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
         final boolean isProxyTrusted = mContext.checkPermission(
                 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 3711679..7837e6e 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -286,7 +286,7 @@
             for (UserHandle user : users) {
                 if (user == null) continue;
 
-                list.add(UserHandle.getUid(user, app.getKey()));
+                list.add(user.getUid(app.getKey()));
             }
         }
         try {
@@ -555,7 +555,7 @@
                     final UserHandle handle = UserHandle.of(userId);
                     if (handle == null) continue;
 
-                    final int uid = UserHandle.getUid(handle, appId);
+                    final int uid = handle.getUid(appId);
                     if (range.contains(uid)) {
                         result.add(uid);
                     }
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index dedf2e2..049a339 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -49,10 +49,7 @@
         switch (cmd.getOpcode()) {
             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
                 mState = STATE_ARC_TERMINATED;
-                audioSystem().setArcStatus(false);
-                if (audioSystem().getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
-                    audioSystem().routeToInputFromPortId(audioSystem().getRoutingPort());
-                }
+                audioSystem().processArcTermination();
                 finish();
                 return true;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 345aa27..39a9119 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -570,8 +570,7 @@
     @ServiceThreadOnly
     protected boolean handleReportArcTermination(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        // TODO(amyjojo): implement report arc terminate handler
-        HdmiLogger.debug(TAG + "Stub handleReportArcTermination");
+        processArcTermination();
         return true;
     }
 
@@ -916,6 +915,14 @@
         mArcEstablished = enabled;
     }
 
+    void processArcTermination() {
+        setArcStatus(false);
+        // Switch away from ARC input when ARC is terminated.
+        if (getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
+            routeToInputFromPortId(getRoutingPort());
+        }
+    }
+
     /** Switch hardware ARC circuit in the system. */
     @ServiceThreadOnly
     private void enableAudioReturnChannel(boolean enabled) {
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 5bd3c57..8017a44 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -841,6 +841,9 @@
     }
 
     private void injectBestLocation(Location location) {
+        if (location.isFromMockProvider()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "injectBestLocation: " + location);
         }
@@ -942,6 +945,9 @@
     }
 
     private void injectLocation(Location location) {
+        if (location.isFromMockProvider()) {
+            return;
+        }
         if (location.hasAccuracy()) {
             if (DEBUG) {
                 Log.d(TAG, "injectLocation: " + location);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f96fa09..14d9d85 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -3488,7 +3488,7 @@
         }
 
         @Override
-        public boolean armRebootEscrow() {
+        public @ArmRebootEscrowErrorCode int armRebootEscrow() {
             return mRebootEscrowManager.armRebootEscrowIfNeeded();
         }
 
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 76ecc1a..c01523a 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -18,6 +18,15 @@
 
 import static android.os.UserHandle.USER_SYSTEM;
 
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+import static com.android.internal.widget.LockSettingsInternal.ArmRebootEscrowErrorCode;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -577,16 +586,14 @@
         mRebootEscrowWanted = false;
         setRebootEscrowReady(false);
 
-
         RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
         if (rebootEscrowProvider == null) {
-            Slog.w(TAG,
-                    "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
-            return;
+            Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
+        } else {
+            rebootEscrowProvider.clearRebootEscrowKey();
         }
 
         clearMetricsStorage();
-        rebootEscrowProvider.clearRebootEscrowKey();
 
         List<UserInfo> users = mUserManager.getUsers();
         for (UserInfo user : users) {
@@ -596,20 +603,30 @@
         mEventLog.addEntry(RebootEscrowEvent.CLEARED_LSKF_REQUEST);
     }
 
-    boolean armRebootEscrowIfNeeded() {
+    @ArmRebootEscrowErrorCode int armRebootEscrowIfNeeded() {
         if (!mRebootEscrowReady) {
-            return false;
+            return ARM_REBOOT_ERROR_ESCROW_NOT_READY;
         }
 
         RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
         if (rebootEscrowProvider == null) {
             Slog.w(TAG,
                     "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
-            return false;
+            clearRebootEscrowIfNeeded();
+            return ARM_REBOOT_ERROR_NO_PROVIDER;
         }
 
+        int expectedProviderType = mInjector.serverBasedResumeOnReboot()
+                ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
+                : RebootEscrowProviderInterface.TYPE_HAL;
         int actualProviderType = rebootEscrowProvider.getType();
-        // TODO(b/183140900) Fail the reboot if provider type mismatches.
+        if (expectedProviderType != actualProviderType) {
+            Slog.w(TAG, "Expect reboot escrow provider " + expectedProviderType
+                    + ", but the RoR is prepared with " + actualProviderType
+                    + ". Please prepare the RoR again.");
+            clearRebootEscrowIfNeeded();
+            return ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+        }
 
         RebootEscrowKey escrowKey;
         synchronized (mKeyGenerationLock) {
@@ -618,30 +635,38 @@
 
         if (escrowKey == null) {
             Slog.e(TAG, "Escrow key is null, but escrow was marked as ready");
-            return false;
+            clearRebootEscrowIfNeeded();
+            return ARM_REBOOT_ERROR_NO_ESCROW_KEY;
         }
 
         // We will use the same key from keystore to encrypt the escrow key and escrow data blob.
         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
         if (kk == null) {
             Slog.e(TAG, "Failed to get encryption key from keystore.");
-            return false;
-        }
-        boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
-        if (armedRebootEscrow) {
-            mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
-            mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
-                    USER_SYSTEM);
-            // Store the vbmeta digest of both slots.
-            mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
-                    USER_SYSTEM);
-            mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
-                    mInjector.getVbmetaDigest(true), USER_SYSTEM);
-            mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
-            mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
+            clearRebootEscrowIfNeeded();
+            return ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
         }
 
-        return armedRebootEscrow;
+        // TODO(b/183140900) design detailed errors for store escrow key errors.
+        // We don't clear rebootEscrow here, because some errors may be recoverable, e.g. network
+        // unavailable for server based provider.
+        boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
+        if (!armedRebootEscrow) {
+            return ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+        }
+
+        mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
+        mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
+                USER_SYSTEM);
+        // Store the vbmeta digest of both slots.
+        mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
+                USER_SYSTEM);
+        mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+                mInjector.getVbmetaDigest(true), USER_SYSTEM);
+        mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
+        mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
+
+        return ARM_REBOOT_ERROR_NONE;
     }
 
     private void setRebootEscrowReady(boolean ready) {
@@ -663,10 +688,6 @@
     }
 
     boolean clearRebootEscrow() {
-        if (mInjector.getRebootEscrowProvider() == null) {
-            return false;
-        }
-
         clearRebootEscrowIfNeeded();
         return true;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 58ffba2..48fee0b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -33,6 +33,8 @@
 import static android.content.Intent.EXTRA_VERSION_CODE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
+import static android.content.Intent.CATEGORY_BROWSABLE;
+import static android.content.Intent.CATEGORY_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 6ea030f..81a51e2 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -25,6 +25,8 @@
 import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode;
 import static android.os.UserHandle.USER_SYSTEM;
 
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.IntentSender;
@@ -47,6 +49,7 @@
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -143,7 +146,7 @@
      */
     @IntDef({ ROR_NEED_PREPARATION,
             ROR_SKIP_PREPARATION_AND_NOTIFY,
-            ROR_SKIP_PREPARATION_NOT_NOTIFY})
+            ROR_SKIP_PREPARATION_NOT_NOTIFY })
     private @interface ResumeOnRebootActionsOnRequest {}
 
     /**
@@ -151,10 +154,43 @@
      */
     @IntDef({ ROR_NOT_REQUESTED,
             ROR_REQUESTED_NEED_CLEAR,
-            ROR_REQUESTED_SKIP_CLEAR})
+            ROR_REQUESTED_SKIP_CLEAR })
     private @interface ResumeOnRebootActionsOnClear {}
 
     /**
+     * Fatal arm escrow errors from lock settings that means the RoR is in a bad state. So clients
+     * need to prepare RoR again.
+     */
+    static final FastImmutableArraySet<Integer> FATAL_ARM_ESCROW_ERRORS =
+            new FastImmutableArraySet<>(new Integer[]{
+                    LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY,
+                    LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER,
+                    LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH,
+                    LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY,
+                    LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE,
+            });
+
+    /**
+     * The error details for ArmRebootEscrow. It contains error codes from RecoverySystemService
+     * and LockSettingsService.
+     */
+    static class RebootPreparationError {
+        final @ResumeOnRebootRebootErrorCode int mRebootErrorCode;
+        final int mProviderErrorCode;  // The supplemental error code from lock settings
+
+        RebootPreparationError(int rebootErrorCode, int providerErrorCode) {
+            mRebootErrorCode = rebootErrorCode;
+            mProviderErrorCode = providerErrorCode;
+        }
+
+        int getErrorCodeForMetrics() {
+            // The ResumeOnRebootRebootErrorCode are aligned with 1000; so it's safe to add them
+            // for metrics purpose.
+            return mRebootErrorCode + mProviderErrorCode;
+        }
+    }
+
+    /**
      * Manages shared preference, i.e. the storage used for metrics reporting.
      */
     public static class PreferencesManager {
@@ -709,34 +745,40 @@
         return true;
     }
 
-    private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
+    private RebootPreparationError armRebootEscrow(String packageName,
             boolean slotSwitch) {
         if (packageName == null) {
             Slog.w(TAG, "Missing packageName when rebooting with lskf.");
-            return RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
+            return new RebootPreparationError(
+                    RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME, ARM_REBOOT_ERROR_NONE);
         }
         if (!isLskfCaptured(packageName)) {
-            return RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+            return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED,
+                    ARM_REBOOT_ERROR_NONE);
         }
 
         if (!verifySlotForNextBoot(slotSwitch)) {
-            return RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
+            return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH,
+                    ARM_REBOOT_ERROR_NONE);
         }
 
         final long origId = Binder.clearCallingIdentity();
-        boolean result;
+        int providerErrorCode;
         try {
-            result = mInjector.getLockSettingsService().armRebootEscrow();
+            providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow();
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
 
-        if (!result) {
-            Slog.w(TAG, "Failure to escrow key for reboot");
-            return RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
+        if (providerErrorCode != ARM_REBOOT_ERROR_NONE) {
+            Slog.w(TAG, "Failure to escrow key for reboot, providerErrorCode: "
+                    + providerErrorCode);
+            return new RebootPreparationError(
+                    RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE, providerErrorCode);
         }
 
-        return RESUME_ON_REBOOT_REBOOT_ERROR_NONE;
+        return new RebootPreparationError(RESUME_ON_REBOOT_REBOOT_ERROR_NONE,
+                ARM_REBOOT_ERROR_NONE);
     }
 
     private boolean useServerBasedRoR() {
@@ -750,7 +792,7 @@
     }
 
     private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
-            @ResumeOnRebootRebootErrorCode int errorCode) {
+            RebootPreparationError escrowError) {
         int uid = mInjector.getUidFromPackageName(packageName);
         boolean serverBased = useServerBasedRoR();
         int preparedClientCount;
@@ -773,15 +815,31 @@
                         + " request count %d, lskf captured count %d, duration since lskf captured"
                         + " %d seconds.", packageName, preparedClientCount, requestCount,
                 lskfCapturedCount, durationSeconds));
-        mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
-                requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount);
+        mInjector.reportRebootEscrowRebootMetrics(escrowError.getErrorCodeForMetrics(), uid,
+                preparedClientCount, requestCount, slotSwitch, serverBased, durationSeconds,
+                lskfCapturedCount);
+    }
+
+    private void clearRoRPreparationStateOnRebootFailure(RebootPreparationError escrowError) {
+        if (!FATAL_ARM_ESCROW_ERRORS.contains(escrowError.mProviderErrorCode)) {
+            return;
+        }
+
+        Slog.w(TAG, "Clearing resume on reboot states for all clients on arm escrow error: "
+                + escrowError.mProviderErrorCode);
+        synchronized (this) {
+            mCallerPendingRequest.clear();
+            mCallerPreparedForReboot.clear();
+        }
     }
 
     private @ResumeOnRebootRebootErrorCode int rebootWithLskfImpl(String packageName, String reason,
             boolean slotSwitch) {
-        @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
-        reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);
+        RebootPreparationError escrowError = armRebootEscrow(packageName, slotSwitch);
+        reportMetricsOnRebootWithLskf(packageName, slotSwitch, escrowError);
+        clearRoRPreparationStateOnRebootFailure(escrowError);
 
+        @ResumeOnRebootRebootErrorCode int errorCode = escrowError.mRebootErrorCode;
         if (errorCode != RESUME_ON_REBOOT_REBOOT_ERROR_NONE) {
             return errorCode;
         }
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 83ac36f..1d55ba4 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -23,6 +23,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
@@ -57,7 +58,6 @@
 import android.net.ipsec.ike.IkeSessionCallback;
 import android.net.ipsec.ike.IkeSessionConfiguration;
 import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -1051,12 +1051,21 @@
         sessionLostWithoutCallback(token, exception);
     }
 
+    private static boolean isIkeAuthFailure(@NonNull Exception exception) {
+        if (!(exception instanceof IkeProtocolException)) {
+            return false;
+        }
+
+        return ((IkeProtocolException) exception).getErrorType()
+                == ERROR_TYPE_AUTHENTICATION_FAILED;
+    }
+
     private void notifyStatusCallbackForSessionClosed(@NonNull Exception exception) {
         final int errorCode;
         final String exceptionClass;
         final String exceptionMessage;
 
-        if (exception instanceof AuthenticationFailedException) {
+        if (isIkeAuthFailure(exception)) {
             errorCode = VCN_ERROR_CODE_CONFIG_ERROR;
             exceptionClass = exception.getClass().getName();
             exceptionMessage = exception.getMessage();
diff --git a/services/core/java/com/android/server/vcn/util/MtuUtils.java b/services/core/java/com/android/server/vcn/util/MtuUtils.java
index 49c1a02..5d40cca 100644
--- a/services/core/java/com/android/server/vcn/util/MtuUtils.java
+++ b/services/core/java/com/android/server/vcn/util/MtuUtils.java
@@ -113,7 +113,6 @@
             return IPV6_MIN_MTU;
         }
 
-        boolean hasUnknownAlgorithm = false;
         int maxAuthOverhead = 0;
         int maxCryptOverhead = 0;
         int maxAuthCryptOverhead = 0;
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 5fde550..7a6d310 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -191,19 +191,18 @@
     static std::array<std::atomic<HalSupport>,
                       static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT) + 1>
             boostSupportedArray = {HalSupport::UNKNOWN};
+    size_t idx = static_cast<size_t>(boost);
 
     // Quick return if boost is not supported by HAL
-    if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
-        boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+    if (idx >= boostSupportedArray.size() || boostSupportedArray[idx] == HalSupport::OFF) {
         ALOGV("Skipped setPowerBoost %s because HAL doesn't support it", toString(boost).c_str());
         return;
     }
 
-    if (boostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
+    if (boostSupportedArray[idx] == HalSupport::UNKNOWN) {
         bool isSupported = false;
         handle->isBoostSupported(boost, &isSupported);
-        boostSupportedArray[static_cast<int32_t>(boost)] =
-            isSupported ? HalSupport::ON : HalSupport::OFF;
+        boostSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
             ALOGV("Skipped setPowerBoost %s because HAL doesn't support it",
                   toString(boost).c_str());
@@ -231,19 +230,18 @@
     // Need to increase the array if more mode supported.
     static std::array<std::atomic<HalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE) + 1>
             modeSupportedArray = {HalSupport::UNKNOWN};
+    size_t idx = static_cast<size_t>(mode);
 
     // Quick return if mode is not supported by HAL
-    if (mode > Mode::DISPLAY_INACTIVE ||
-        modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+    if (idx >= modeSupportedArray.size() || modeSupportedArray[idx] == HalSupport::OFF) {
         ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
         return false;
     }
 
-    if (modeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
+    if (modeSupportedArray[idx] == HalSupport::UNKNOWN) {
         bool isSupported = false;
         handle->isModeSupported(mode, &isSupported);
-        modeSupportedArray[static_cast<int32_t>(mode)] =
-            isSupported ? HalSupport::ON : HalSupport::OFF;
+        modeSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
             ALOGV("Skipped setPowerMode %s because HAL doesn't support it", toString(mode).c_str());
             return false;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index 691d174..f2bb1d6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -87,6 +87,11 @@
     }
 
     @Override
+    String getRebootEscrowFile(int userId) {
+        return makeDirs(mStorageDir, super.getRebootEscrowFile(userId)).getAbsolutePath();
+    }
+
+    @Override
     protected File getSyntheticPasswordDirectoryForUser(int userId) {
         return makeDirs(mStorageDir, super.getSyntheticPasswordDirectoryForUser(
                 userId).getAbsolutePath());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 8c08226..49a54ec 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -21,6 +21,11 @@
 import static android.content.pm.UserInfo.FLAG_PROFILE;
 import static android.os.UserHandle.USER_SYSTEM;
 
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -327,7 +332,7 @@
 
         assertNull(
                 mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         assertNotNull(
                 mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
         verify(mRebootEscrow).storeKey(any());
@@ -351,7 +356,7 @@
 
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
 
         assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -373,7 +378,7 @@
         assertNull(
                 mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
         doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
-        assertFalse(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
         verify(mRebootEscrow).storeKey(any());
     }
 
@@ -396,7 +401,7 @@
 
         assertNull(
                 mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         assertNotNull(
                 mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
         verify(mRebootEscrow, times(1)).storeKey(any());
@@ -408,15 +413,24 @@
 
     @Test
     public void armService_NoInitialization_Failure() throws Exception {
-        assertFalse(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_ESCROW_NOT_READY, mService.armRebootEscrowIfNeeded());
         verifyNoMoreInteractions(mRebootEscrow);
     }
 
     @Test
     public void armService_RebootEscrowServiceException_Failure() throws Exception {
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mRebootEscrow);
+        mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mRebootEscrow, never()).storeKey(any());
+
         doThrow(RemoteException.class).when(mRebootEscrow).storeKey(any());
-        assertFalse(mService.armRebootEscrowIfNeeded());
-        verifyNoMoreInteractions(mRebootEscrow);
+        assertEquals(ARM_REBOOT_ERROR_STORE_ESCROW_KEY, mService.armRebootEscrowIfNeeded());
+        verify(mRebootEscrow).storeKey(any());
     }
 
     @Test
@@ -439,7 +453,7 @@
         verify(mRebootEscrow, never()).storeKey(any());
 
         ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
         verify(mKeyStoreManager).getKeyStoreEncryptionKey();
 
@@ -483,7 +497,7 @@
         // Use x -> x for both wrap & unwrap functions.
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
         assertTrue(mStorage.hasRebootEscrowServerBlob());
 
@@ -520,7 +534,7 @@
         // Use x -> x for both wrap & unwrap functions.
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
         assertTrue(mStorage.hasRebootEscrowServerBlob());
 
@@ -557,7 +571,7 @@
         // Use x -> x for both wrap & unwrap functions.
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
         assertTrue(mStorage.hasRebootEscrowServerBlob());
 
@@ -597,7 +611,7 @@
         // Use x -> x for both wrap & unwrap functions.
         when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
                 .thenAnswer(invocation -> invocation.getArgument(0));
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
         assertTrue(mStorage.hasRebootEscrowServerBlob());
 
@@ -635,7 +649,7 @@
 
         verify(mRebootEscrow, never()).storeKey(any());
 
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mRebootEscrow).storeKey(any());
 
         assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -695,7 +709,7 @@
         verify(mRebootEscrow, never()).storeKey(any());
 
         ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class);
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mRebootEscrow).storeKey(keyByteCaptor.capture());
 
         assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -732,8 +746,7 @@
         verify(mockListener).onPreparedForReboot(eq(true));
 
         verify(mRebootEscrow, never()).storeKey(any());
-
-        assertTrue(mService.armRebootEscrowIfNeeded());
+        assertEquals(ARM_REBOOT_ERROR_NONE, mService.armRebootEscrowIfNeeded());
         verify(mRebootEscrow).storeKey(any());
 
         assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
@@ -756,4 +769,28 @@
         assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
                 metricsErrorCodeCaptor.getValue());
     }
+
+    @Test
+    public void armServiceProviderMismatch_Failure() throws Exception {
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mRebootEscrow);
+        mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+        verify(mRebootEscrow, never()).storeKey(any());
+
+        assertNull(
+                mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+        // Change the provider to server based, expect the reboot to fail
+        when(mInjected.forceServerBased()).thenReturn(true);
+        assertEquals(ARM_REBOOT_ERROR_PROVIDER_MISMATCH, mService.armRebootEscrowIfNeeded());
+        assertNull(
+                mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+        // Verify that the escrow key & data have been cleared.
+        verify(mRebootEscrow).storeKey(eq(new byte[32]));
+        assertFalse(mStorage.hasRebootEscrow(PRIMARY_USER_ID));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index 2b358ea..b64810b 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -18,11 +18,14 @@
 
 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_INVALID_PACKAGE_NAME;
 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_LSKF_NOT_CAPTURED;
+import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE;
 import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMATCH;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -31,6 +34,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -91,7 +95,8 @@
         mUncryptUpdateFileWriter = mock(FileWriter.class);
         mLockSettingsInternal = mock(LockSettingsInternal.class);
 
-        when(mLockSettingsInternal.armRebootEscrow()).thenReturn(true);
+        doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_NONE).when(mLockSettingsInternal)
+                .armRebootEscrow();
 
         Looper looper = InstrumentationRegistry.getContext().getMainLooper();
         mIPowerManager = mock(IPowerManager.class);
@@ -489,4 +494,27 @@
     }
 
     // TODO(xunchang) add more multi client tests
+
+    @Test
+    public void rebootWithLskf_armEscrowDataFatalError_Failure() throws Exception {
+        doReturn(LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH)
+                .when(mLockSettingsInternal).armRebootEscrow();
+
+        assertTrue(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null));
+        mRecoverySystemService.onPreparedForReboot(true);
+        assertTrue(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+
+        when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME
+                + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(1);
+        when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF),
+                anyInt())).thenReturn(1);
+        assertEquals(RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
+                mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true));
+        // Verify that the RoR preparation state has been cleared.
+        assertFalse(mRecoverySystemService.isLskfCaptured(FAKE_OTA_PACKAGE_NAME));
+        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(5004 /* provider mismatch */),
+                eq(1000), eq(1) /* client count */, eq(1) /* request count */,
+                eq(true) /* slot switch */, anyBoolean(), anyInt(),
+                eq(1) /* lskf capture count */);
+    }
 }
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index f6d18fc..96e715e 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -637,18 +637,18 @@
             this.band = band;
             this.downlinkLowKhz = downlinkLowKhz;
             this.downlinkOffset = downlinkOffset;
+            this.downlinkRange = downlinkRange;
             this.uplinkLowKhz = uplinkLowKhz;
             this.uplinkOffset = uplinkOffset;
-            this.downlinkRange = downlinkRange;
             this.uplinkRange = uplinkRange;
         }
 
         int band;
         int downlinkLowKhz;
         int downlinkOffset;
+        int downlinkRange;
         int uplinkLowKhz;
         int uplinkOffset;
-        int downlinkRange;
         int uplinkRange;
     }
 
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index f29f3bd..6b82045 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -598,7 +598,8 @@
                             : earfcnFrequency.downlinkOffset;
                     break;
                 } else {
-                    Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+                    Rlog.w(TAG,"Band and the range of EARFCN are not consistent: band = " + band
+                            + " ,earfcn = " + earfcn + " ,isUplink = " + isUplink);
                     return INVALID_FREQUENCY;
                 }
             }
@@ -617,7 +618,7 @@
     }
 
     private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
-                                           boolean isUplink) {
+            boolean isUplink) {
         if (isUplink) {
             return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
         } else {
@@ -640,7 +641,8 @@
                             : uarfcnFrequency.downlinkOffset;
                     break;
                 } else {
-                    Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+                    Rlog.w(TAG,"Band and the range of UARFCN are not consistent: band = " + band
+                            + " ,uarfcn = " + uarfcn + " ,isUplink = " + isUplink);
                     return INVALID_FREQUENCY;
                 }
             }
@@ -716,7 +718,8 @@
                             arfcnOffset);
                     break;
                 } else {
-                    Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+                    Rlog.w(TAG,"Band and the range of ARFCN are not consistent: band = " + band
+                            + " ,arfcn = " + arfcn + " ,isUplink = " + isUplink);
                     return INVALID_FREQUENCY;
                 }
             }
@@ -733,7 +736,7 @@
      * Downlink actual frequency(kHz) = Uplink actual frequency + 10
      */
     private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
-                                               int arfcnOffset) {
+            int arfcnOffset) {
         return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
     }
 
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index d21fcab..391372a 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -203,23 +203,6 @@
     }
 
     /**
-     * @return the UTF-8 encoded SIP message.
-     * @deprecated Use {@link #toEncodedMessage} instead
-     */
-    @Deprecated
-    public @NonNull byte[] getEncodedMessage() {
-        byte[] header = new StringBuilder()
-                .append(mStartLine)
-                .append(mHeaderSection)
-                .append(CRLF)
-                .toString().getBytes(UTF_8);
-        byte[] sipMessage = new byte[header.length + mContent.length];
-        System.arraycopy(header, 0, sipMessage, 0, header.length);
-        System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
-        return sipMessage;
-    }
-
-    /**
      * According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
      * consists of a start-line, one or more header fields, an empty line indicating the end of the
      * header fields, and an optional message-body.
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index db939f9..454d5b5 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -63,8 +63,10 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
             setLegacyTypeName("TEST_NETWORK")
-            setNat64DetectionEnabled(false)
-            setProvisioningNotificationEnabled(false)
+            if (isAtLeastS()) {
+                setNat64DetectionEnabled(false)
+                setProvisioningNotificationEnabled(false)
+            }
         }.build()
 
         assertTrue(config.isExplicitlySelected())
@@ -73,7 +75,12 @@
         assertFalse(config.isPartialConnectivityAcceptable())
         assertTrue(config.isUnvalidatedConnectivityAcceptable())
         assertEquals("TEST_NETWORK", config.getLegacyTypeName())
-        assertFalse(config.isNat64DetectionEnabled())
-        assertFalse(config.isProvisioningNotificationEnabled())
+        if (isAtLeastS()) {
+            assertFalse(config.isNat64DetectionEnabled())
+            assertFalse(config.isProvisioningNotificationEnabled())
+        } else {
+            assertTrue(config.isNat64DetectionEnabled())
+            assertTrue(config.isProvisioningNotificationEnabled())
+        }
     }
 }
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index fec5ef3..d7535a9 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -197,7 +197,7 @@
         } else {
             pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
         }
-        pkgInfo.applicationInfo.uid = UserHandle.getUid(user, UserHandle.getAppId(uid));
+        pkgInfo.applicationInfo.uid = user.getUid(UserHandle.getAppId(uid));
         return pkgInfo;
     }
 
@@ -390,7 +390,7 @@
         public void expectPermission(Boolean permission, UserHandle[] users, int[] apps) {
             for (final UserHandle user : users) {
                 for (final int app : apps) {
-                    final int uid = UserHandle.getUid(user, app);
+                    final int uid = user.getUid(app);
                     if (!mApps.containsKey(uid)) {
                         fail("uid " + uid + " does not exist.");
                     }
@@ -404,7 +404,7 @@
         public void expectNoPermission(UserHandle[] users, int[] apps) {
             for (final UserHandle user : users) {
                 for (final int app : apps) {
-                    final int uid = UserHandle.getUid(user, app);
+                    final int uid = user.getUid(app);
                     if (mApps.containsKey(uid)) {
                         fail("uid " + uid + " has listed permissions, expected none.");
                     }
@@ -502,9 +502,9 @@
 
         // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
         mPermissionMonitor.onPackageRemoved(
-                MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+                MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
-        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
         verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
                 aryEq(new int[] {MOCK_UID1}));
 
@@ -541,13 +541,13 @@
         mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
 
         // Newly-installed package should have uid rules added
-        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+        mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
         verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
                 aryEq(new int[] {MOCK_UID1}));
 
         // Removed package should have its uid rules removed
         mPermissionMonitor.onPackageRemoved(
-                MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+                MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
         verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
     }
 
@@ -557,13 +557,13 @@
     // called multiple times with the uid corresponding to each user.
     private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
         for (final UserHandle user : users) {
-            mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
+            mPermissionMonitor.onPackageAdded(packageName, user.getUid(uid));
         }
     }
 
     private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
         for (final UserHandle user : users) {
-            mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid));
+            mPermissionMonitor.onPackageRemoved(packageName, user.getUid(uid));
         }
     }
 
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index bb67593..a2223e8 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -20,6 +20,8 @@
 import static android.net.IpSecManager.DIRECTION_OUT;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
+import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_TEMPORARY_FAILURE;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_CONFIG_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
@@ -41,6 +43,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
@@ -48,10 +51,9 @@
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.exceptions.AuthenticationFailedException;
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeInternalException;
-import android.net.ipsec.ike.exceptions.TemporaryFailureException;
+import android.net.ipsec.ike.exceptions.IkeProtocolException;
 import android.net.vcn.VcnControlPlaneIkeConfig;
 import android.net.vcn.VcnManager.VcnErrorCode;
 
@@ -470,10 +472,17 @@
                         any());
     }
 
+    private static IkeProtocolException buildMockIkeProtocolException(int errorCode) {
+        final IkeProtocolException exception = mock(IkeProtocolException.class);
+        when(exception.getErrorType()).thenReturn(errorCode);
+        return exception;
+    }
+
     @Test
     public void testIkeSessionClosedExceptionallyAuthenticationFailure() throws Exception {
         verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
-                new AuthenticationFailedException("vcn test"), VCN_ERROR_CODE_CONFIG_ERROR);
+                buildMockIkeProtocolException(ERROR_TYPE_AUTHENTICATION_FAILED),
+                VCN_ERROR_CODE_CONFIG_ERROR);
     }
 
     @Test
@@ -485,7 +494,8 @@
     @Test
     public void testIkeSessionClosedExceptionallyInternalFailure() throws Exception {
         verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
-                new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
+                buildMockIkeProtocolException(ERROR_TYPE_TEMPORARY_FAILURE),
+                VCN_ERROR_CODE_INTERNAL_ERROR);
     }
 
     @Test
diff --git a/tools/fonts/Android.bp b/tools/fonts/Android.bp
new file mode 100644
index 0000000..bf50661
--- /dev/null
+++ b/tools/fonts/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2021 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.
+
+python_defaults {
+    name: "fonts_python_defaults",
+    version: {
+        py2: {
+            enabled: false,
+            embedded_launcher: false,
+        },
+        py3: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+    },
+}
+
+python_binary_host {
+    name: "fontchain_linter",
+    defaults: ["fonts_python_defaults"],
+    main: "fontchain_linter.py",
+    srcs: [
+        "fontchain_linter.py",
+    ],
+    libs: [
+        "fontTools",
+    ],
+}
diff --git a/tools/hiddenapi/checksorted_sha.sh b/tools/hiddenapi/checksorted_sha.sh
index 451fed6..72fb867 100755
--- a/tools/hiddenapi/checksorted_sha.sh
+++ b/tools/hiddenapi/checksorted_sha.sh
@@ -1,10 +1,10 @@
 #!/bin/bash
 set -e
 LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
-git show --name-only --pretty=format: $1 | grep "boot/hiddenapi/hiddenapi-.*txt" | while read file; do
+git show --name-only --pretty=format: $1 | grep "hiddenapi/hiddenapi-.*txt" | while read file; do
     diff <(git show $1:$file) <(git show $1:$file | $LOCAL_DIR/sort_api.sh )  || {
       echo -e "\e[1m\e[31m$file $1 is not sorted or contains duplicates. To sort it correctly:\e[0m"
-      echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $2/frameworks/base/$file\e[0m"
+      echo -e "\e[33m${LOCAL_DIR}/sort_api.sh $PWD/$file\e[0m"
       exit 1
     }
 done
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 822aba4..8b18f9b 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -10,7 +10,6 @@
   android.system \
   android.test \
   com.android.bouncycastle \
-  com.android.i18n.phonenumbers \
   com.android.okhttp \
   com.sun \
   dalvik \